Merge branch 'master' of https://git.frogeye.fr/geoffrey/dotfiles
This commit is contained in:
commit
59fdfe7ea2
6
config/mypy/config
Normal file
6
config/mypy/config
Normal file
|
@ -0,0 +1,6 @@
|
|||
[mypy]
|
||||
ignore_missing_imports = True
|
||||
disallow_untyped_defs = True
|
||||
disallow_untyped_calls = True
|
||||
disallow_incomplete_defs = True
|
||||
disallow_untyped_decorators = True
|
|
@ -603,6 +603,6 @@ if __name__ == "__main__":
|
|||
perfstep("exec")
|
||||
|
||||
# DEBUG
|
||||
sys.exit(0)
|
||||
for kv in sorted(perf_dict.items(), key=lambda p: p[1]):
|
||||
log.debug("{1:.6f} {0}".format(*kv))
|
||||
sys.exit(0)
|
||||
|
|
59
config/scripts/ovhcli
Executable file
59
config/scripts/ovhcli
Executable file
|
@ -0,0 +1,59 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import os
|
||||
import ovh
|
||||
import xdg.BaseDirectory
|
||||
import urllib.request
|
||||
from pprint import pprint
|
||||
import json
|
||||
import logging
|
||||
import coloredlogs
|
||||
import argparse
|
||||
|
||||
coloredlogs.install(level='DEBUG', fmt='%(levelname)s %(message)s')
|
||||
log = logging.getLogger()
|
||||
|
||||
debug = None
|
||||
|
||||
class OvhCli():
|
||||
ROOT = "https://api.ovh.com/1.0?null"
|
||||
def __init__(self):
|
||||
self.cacheDir = os.path.join(xdg.BaseDirectory.xdg_cache_home, 'ovhcli')
|
||||
# TODO Corner cases: links, cache dir not done, configurable cache
|
||||
if not os.path.isdir(self.cacheDir):
|
||||
assert not os.path.exists(self.cacheDir)
|
||||
os.makedirs(self.cacheDir)
|
||||
|
||||
def updateCache(self):
|
||||
log.info("Downloading the API description")
|
||||
rootJsonPath = os.path.join(self.cacheDir, 'root.json')
|
||||
log.debug(f"{self.ROOT} -> {rootJsonPath}")
|
||||
urllib.request.urlretrieve(self.ROOT, rootJsonPath)
|
||||
with open(rootJsonPath, 'rt') as rootJson:
|
||||
root = json.load(rootJson)
|
||||
basePath = root['basePath']
|
||||
|
||||
for apiRoot in root['apis']:
|
||||
fmt = 'json'
|
||||
assert fmt in apiRoot['format']
|
||||
path = apiRoot['path']
|
||||
schema = apiRoot['schema'].format(format=fmt, path=path)
|
||||
apiJsonPath = os.path.join(self.cacheDir, schema[1:])
|
||||
apiJsonUrl = basePath + schema
|
||||
log.debug(f"{apiJsonUrl} -> {apiJsonPath}")
|
||||
apiJsonPathDir = os.path.dirname(apiJsonPath)
|
||||
if not os.path.isdir(apiJsonPathDir):
|
||||
os.makedirs(apiJsonPathDir)
|
||||
urllib.request.urlretrieve(apiJsonUrl, apiJsonPath)
|
||||
|
||||
def createParser(self):
|
||||
parser = argparse.ArgumentParser(description='Access the OVH API')
|
||||
return parser
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
cli = OvhCli()
|
||||
# cli.updateCache()
|
||||
parser = cli.createParser()
|
||||
args = parser.parse_args()
|
||||
print(args)
|
|
@ -13,7 +13,7 @@ import progressbar
|
|||
import logging
|
||||
|
||||
progressbar.streams.wrap_stderr()
|
||||
coloredlogs.install(level='INFO', fmt='%(levelname)s %(message)s')
|
||||
coloredlogs.install(level='DEBUG', fmt='%(levelname)s %(message)s')
|
||||
log = logging.getLogger()
|
||||
|
||||
# 1) Create file list with conflict files
|
||||
|
@ -34,12 +34,24 @@ class Table():
|
|||
def __init__(self, width, height):
|
||||
self.width = width
|
||||
self.height = height
|
||||
self.data = [['' ** self.height] ** self.width]
|
||||
self.data = [['' for _ in range(self.height)]
|
||||
for _ in range(self.width)]
|
||||
|
||||
def set(x, y, data):
|
||||
def set(self, x, y, data):
|
||||
self.data[x][y] = str(data)
|
||||
|
||||
|
||||
def print(self):
|
||||
widths = [max([len(cell) for cell in column]) for column in self.data]
|
||||
for y in range(self.height):
|
||||
for x in range(self.width):
|
||||
cell = self.data[x][y]
|
||||
l = len(cell)
|
||||
width = widths[x]
|
||||
if x > 0:
|
||||
cell = ' | ' + cell
|
||||
cell = cell + ' ' * (width - l)
|
||||
print(cell, end='\t')
|
||||
print()
|
||||
|
||||
|
||||
class Database():
|
||||
|
@ -137,7 +149,8 @@ class Database():
|
|||
max_value=self.totalChecksumSize(), widgets=widgets).start()
|
||||
f = 0
|
||||
for databaseFile in self.data.values():
|
||||
bar.update(f, dir=databaseFile.root[(len(self.directory)+1):], file=databaseFile.filename)
|
||||
bar.update(f, dir=databaseFile.root[(
|
||||
len(self.directory)+1):], file=databaseFile.filename)
|
||||
f += databaseFile.totalChecksumSize()
|
||||
try:
|
||||
databaseFile.getChecksums()
|
||||
|
@ -148,14 +161,20 @@ class Database():
|
|||
pass
|
||||
bar.finish()
|
||||
|
||||
def act(self):
|
||||
pass
|
||||
def printDifferences(self):
|
||||
for databaseFile in self.data.values():
|
||||
print()
|
||||
databaseFile.printInfos(diff=True)
|
||||
|
||||
def takeAction(self, execute=False, *args, **kwargs):
|
||||
for databaseFile in self.data.values():
|
||||
databaseFile.decideAction(*args, **kwargs)
|
||||
databaseFile.takeAction(execute=execute)
|
||||
|
||||
|
||||
class DatabaseFile():
|
||||
BLOCK_SIZE = 4096
|
||||
RELEVANT_STATS = ('st_mode', 'st_uid', 'st_gid',
|
||||
'st_size', 'st_mtime', 'st_ctime')
|
||||
RELEVANT_STATS = ('st_mode', 'st_uid', 'st_gid', 'st_size', 'st_mtime')
|
||||
|
||||
def __init__(self, root, filename):
|
||||
self.root = root
|
||||
|
@ -163,6 +182,7 @@ class DatabaseFile():
|
|||
self.stats = []
|
||||
self.conflicts = []
|
||||
self.checksums = []
|
||||
self.action = None
|
||||
log.debug(f"{self.root}/{self.filename} - new")
|
||||
|
||||
def addConflict(self, conflict):
|
||||
|
@ -190,16 +210,16 @@ class DatabaseFile():
|
|||
del self.checksums[f]
|
||||
log.debug(f"{self.root}/{self.filename} - del: {conflict}")
|
||||
|
||||
def getPathFile(self, conflict):
|
||||
def getPath(self, conflict):
|
||||
return os.path.join(self.root, conflict)
|
||||
|
||||
def getPathFiles(self):
|
||||
return [self.getPathFile(conflict) for conflict in self.conflicts]
|
||||
def getPaths(self):
|
||||
return [self.getPath(conflict) for conflict in self.conflicts]
|
||||
|
||||
def prune(self):
|
||||
toPrune = list()
|
||||
for conflict in self.conflicts:
|
||||
if not os.path.isfile(self.getPathFile(conflict)):
|
||||
if not os.path.isfile(self.getPath(conflict)):
|
||||
toPrune.append(conflict)
|
||||
|
||||
if len(toPrune):
|
||||
|
@ -236,7 +256,7 @@ class DatabaseFile():
|
|||
def getStats(self):
|
||||
for f, conflict in enumerate(self.conflicts):
|
||||
oldStat = self.stats[f]
|
||||
newStat = os.stat(self.getPathFile(conflict))
|
||||
newStat = os.stat(self.getPath(conflict))
|
||||
oldChecksum = self.checksums[f]
|
||||
|
||||
# If it's been already summed, and we have the same inode and same ctime, don't resum
|
||||
|
@ -262,7 +282,7 @@ class DatabaseFile():
|
|||
if self.checksums[f] is not None:
|
||||
continue
|
||||
self.checksums[f] = 1
|
||||
filedescs[f] = open(self.getPathFile(conflict), 'rb')
|
||||
filedescs[f] = open(self.getPath(conflict), 'rb')
|
||||
|
||||
while len(filedescs):
|
||||
toClose = set()
|
||||
|
@ -285,10 +305,12 @@ class DatabaseFile():
|
|||
|
||||
def getFeatures(self):
|
||||
features = dict()
|
||||
features['name'] = self.conflicts
|
||||
features['sum'] = self.checksums
|
||||
for stat in DatabaseFile.RELEVANT_STATS:
|
||||
features[stat] = [self.stats[f].__getattribute__(
|
||||
stat) for f in enumerate(self.stats)]
|
||||
for statName in DatabaseFile.RELEVANT_STATS:
|
||||
# Rounding beause I Syncthing also rounds
|
||||
features[statName] = [
|
||||
int(stat.__getattribute__(statName)) for stat in self.stats]
|
||||
return features
|
||||
|
||||
def getDiffFeatures(self):
|
||||
|
@ -299,18 +321,74 @@ class DatabaseFile():
|
|||
diffFeatures[key] = vals
|
||||
return diffFeatures
|
||||
|
||||
def printInfos(self):
|
||||
print(os.path.join(self.root, self.name))
|
||||
@staticmethod
|
||||
def shortConflict(conflict):
|
||||
match = Database.CONFLICT_PATTERN.search(conflict)
|
||||
if match:
|
||||
return match[0][15:]
|
||||
else:
|
||||
return '-'
|
||||
|
||||
# nf = re.sub( '', f)
|
||||
# F = os.path.join(root, f)
|
||||
# NF = os.path.join(root, nf)
|
||||
# if os.path.exists(NF):
|
||||
# print(f"'{F}' → '{NF}': file already exists")
|
||||
# else:
|
||||
# print(f"'{F}' → '{NF}': done")
|
||||
# # os.rename(F, NF)
|
||||
def printInfos(self, diff=True):
|
||||
print(os.path.join(self.root, self.filename))
|
||||
if diff:
|
||||
features = self.getDiffFeatures()
|
||||
else:
|
||||
features = self.getFeatures()
|
||||
features['name'] = [DatabaseFile.shortConflict(
|
||||
c) for c in self.conflicts]
|
||||
table = Table(len(features), len(self.conflicts)+1)
|
||||
for x, featureName in enumerate(features.keys()):
|
||||
table.set(x, 0, featureName)
|
||||
for x, featureName in enumerate(features.keys()):
|
||||
for y in range(len(self.conflicts)):
|
||||
table.set(x, y+1, features[featureName][y])
|
||||
table.print()
|
||||
|
||||
def decideAction(self, mostRecent=False):
|
||||
# TODO More arguments for choosing
|
||||
reason = "undecided"
|
||||
self.action = None
|
||||
if len(self.conflicts) == 1:
|
||||
self.action = 0
|
||||
reason = "only file"
|
||||
else:
|
||||
features = self.getDiffFeatures()
|
||||
if len(features) == 1:
|
||||
reason = "same files"
|
||||
self.action = 0
|
||||
elif 'st_mtime' in features and mostRecent:
|
||||
recentTime = features['st_mtime'][0]
|
||||
recentIndex = 0
|
||||
for index, time in enumerate(features['st_mtime']):
|
||||
if time > recentTime:
|
||||
recentTime = time
|
||||
recentIndex = 0
|
||||
self.action = recentIndex
|
||||
reason = "most recent"
|
||||
|
||||
if self.action is None:
|
||||
log.warning(
|
||||
f"{self.root}/{self.filename}: skip, cause: {reason}")
|
||||
else:
|
||||
log.info(
|
||||
f"{self.root}/{self.filename}: keep {DatabaseFile.shortConflict(self.conflicts[self.action])}, cause: {reason}")
|
||||
|
||||
def takeAction(self, execute=False):
|
||||
if self.action is None:
|
||||
return
|
||||
actionName = self.conflicts[self.action]
|
||||
if actionName != self.filename:
|
||||
log.debug(
|
||||
f"Rename {self.getPath(actionName)} → {self.getPath(self.filename)}")
|
||||
if execute:
|
||||
os.rename(self.getPath(actionName), self.getPath(self.filename))
|
||||
for conflict in self.conflicts:
|
||||
if conflict is actionName:
|
||||
continue
|
||||
log.debug(f"Delete {self.getPath(conflict)}")
|
||||
if execute:
|
||||
os.unlink(self.getPath(conflict))
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
|
@ -318,11 +396,16 @@ if __name__ == "__main__":
|
|||
description="Handle Syncthing's .sync-conflict files ")
|
||||
|
||||
# Execution flow
|
||||
parser.add_argument(
|
||||
'--database', help='Database path for file informations')
|
||||
|
||||
parser.add_argument('directory', metavar='DIRECTORY',
|
||||
nargs='?', help='Directory to analyse')
|
||||
parser.add_argument('-d', '--database',
|
||||
help='Database path for file informations')
|
||||
parser.add_argument('-r', '--most-recent', action='store_true',
|
||||
help='Always keep the most recent version')
|
||||
parser.add_argument('-e', '--execute', action='store_true',
|
||||
help='Really apply changes')
|
||||
parser.add_argument('-p', '--print', action='store_true',
|
||||
help='Only print differences between files')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
|
@ -362,4 +445,7 @@ if __name__ == "__main__":
|
|||
database.getChecksums()
|
||||
saveDatabase()
|
||||
|
||||
database.act()
|
||||
if args.print:
|
||||
database.printDifferences()
|
||||
else:
|
||||
database.takeAction(mostRecent=args.most_recent, execute=args.execute)
|
||||
|
|
|
@ -24,14 +24,15 @@ nmap <F8> :TagbarToggle<CR>
|
|||
set noshowmode
|
||||
set laststatus=2
|
||||
let g:airline_powerline_fonts = 1
|
||||
" let g:airline#extensions#syntastic#enabled = 1
|
||||
let g:airline#extensions#tabline#enabled = 1
|
||||
|
||||
let g:airline_section_a = airline#section#create(['mode'])
|
||||
let g:airline_section_b = airline#section#create(['branch', 'hunks'])
|
||||
" let g:airline_section_z = airline#section#create(['%B', '@', '%l', ':', '%c'])
|
||||
let g:airline_theme = 'base16_monokai'
|
||||
let g:airline#extensions#ale#enabled = 1
|
||||
|
||||
let airline#extensions#languageclient#error_symbol = '✖ '
|
||||
let airline#extensions#languageclient#warning_symbol = '⚠ '
|
||||
|
||||
""" FZF """
|
||||
|
||||
|
@ -51,27 +52,28 @@ let g:fzf_colors =
|
|||
\ 'spinner': ['fg', 'Label'],
|
||||
\ 'header': ['fg', 'Comment'] }
|
||||
|
||||
nmap gF :Files<CR>
|
||||
nmap gf :GFiles<CR>
|
||||
nmap gb :Buffers<CR>
|
||||
nmap gL :Lines<CR>
|
||||
nmap gl :BLines<CR>
|
||||
nmap gT :Tags<CR>
|
||||
nmap gt :BTags<CR>
|
||||
nmap gm :Marks<CR>
|
||||
nmap gw :Windows<CR>
|
||||
nmap gh :History<CR>
|
||||
nmap gH :History:<CR>
|
||||
nmap gS :History/<CR>
|
||||
nmap gs :Snippets<CR>
|
||||
let g:fzf_command_prefix = 'Fzf'
|
||||
nmap gF :FzfFiles<CR>
|
||||
nmap gf :FzfGFiles<CR>
|
||||
nmap gb :FzfBuffers<CR>
|
||||
nmap gL :FzfLines<CR>
|
||||
nmap gl :FzfBLines<CR>
|
||||
nmap gT :FzfTags<CR>
|
||||
nmap gt :FzfBTags<CR>
|
||||
nmap gm :FzfMarks<CR>
|
||||
nmap gw :FzfWindows<CR>
|
||||
nmap gh :FzfHistory<CR>
|
||||
nmap gH :FzfHistory:<CR>
|
||||
nmap gS :FzfHistory/<CR>
|
||||
nmap gs :FzfSnippets<CR>
|
||||
|
||||
" TODO `gd` → go to tag matching selected word, or show a list with that
|
||||
" of tags pre-filtered with that word
|
||||
|
||||
""" SUPERTAB """
|
||||
|
||||
let g:SuperTabDefaultCompletionType = "<c-n>" " Go down when completing
|
||||
let g:SuperTabContextDefaultCompletionType = "<c-n>"
|
||||
" let g:SuperTabDefaultCompletionType = "<c-n>" " Go down when completing
|
||||
" let g:SuperTabContextDefaultCompletionType = "<c-n>"
|
||||
|
||||
""" LanguageTool """
|
||||
|
||||
|
@ -82,3 +84,26 @@ let g:pandoc#modules#disabled = ["folding"]
|
|||
let g:pandoc#spell#enabled = 0
|
||||
let g:pandoc#syntax#conceal#use = 0
|
||||
|
||||
""" LanguageClient-neovim """
|
||||
|
||||
let g:LanguageClient_serverCommands = {
|
||||
\ 'python': ['pyls'],
|
||||
\ }
|
||||
|
||||
|
||||
function LC_maps()
|
||||
if has_key(g:LanguageClient_serverCommands, &filetype)
|
||||
nnoremap <buffer> <silent> K :call LanguageClient#textDocument_hover()<cr>
|
||||
nnoremap <buffer> <silent> gd :call LanguageClient#textDocument_definition()<CR>
|
||||
nnoremap <buffer> <silent> gd :call LanguageClient#textDocument_references()<CR>
|
||||
nnoremap <buffer> <silent> <F2> :call LanguageClient#textDocument_rename()<CR>
|
||||
nnoremap <buffer> <silent> <F3> :call LanguageClient#textDocument_formatting()<CR>
|
||||
set completefunc=LanguageClient#complete
|
||||
set omnifunc=LanguageClient#complete
|
||||
endif
|
||||
endfunction
|
||||
autocmd FileType * call LC_maps()
|
||||
|
||||
""" deoplete """
|
||||
|
||||
let g:deoplete#enable_at_startup = 1
|
|
@ -34,15 +34,24 @@ Plug 'tomtom/tcomment_vim'
|
|||
" Plug 'tomlion/vim-solidity'
|
||||
" Plug 'godlygeek/tabular'
|
||||
" Plug 'jrozner/vim-antlr'
|
||||
|
||||
" When in f/F/t/T mode, highlight in red the characters that can be jumped to
|
||||
Plug 'deris/vim-shot-f'
|
||||
|
||||
" Auto-highlight one character per word for quick f/F movement
|
||||
Plug 'unblevable/quick-scope'
|
||||
|
||||
"
|
||||
" Plug 'maralla/completor.vim'
|
||||
" if has('nvim')
|
||||
" Plug 'Shougo/deoplete.nvim', { 'do': ':UpdateRemotePlugins' }
|
||||
" else
|
||||
" Plug 'Shougo/deoplete.nvim'
|
||||
" Plug 'roxma/nvim-yarp'
|
||||
" Plug 'roxma/vim-hug-neovim-rpc'
|
||||
" endif
|
||||
"
|
||||
" Auto-completion
|
||||
if has('nvim')
|
||||
Plug 'Shougo/deoplete.nvim', { 'do': ':UpdateRemotePlugins' }
|
||||
else
|
||||
Plug 'Shougo/deoplete.nvim'
|
||||
Plug 'roxma/nvim-yarp'
|
||||
Plug 'roxma/vim-hug-neovim-rpc'
|
||||
endif
|
||||
" Plug 'zchee/deoplete-jedi'
|
||||
|
||||
" Plug 'python-mode/python-mode', { 'branch': 'develop' }
|
||||
|
@ -54,7 +63,13 @@ Plug 'terryma/vim-smooth-scroll'
|
|||
Plug 'vim-pandoc/vim-pandoc'
|
||||
Plug 'vim-pandoc/vim-pandoc-syntax'
|
||||
Plug 'idanarye/vim-vebugger'
|
||||
Plug 'w0rp/ale'
|
||||
|
||||
" Language Server Procotol client
|
||||
Plug 'autozimu/LanguageClient-neovim', {
|
||||
\ 'branch': 'next',
|
||||
\ 'do': 'bash install.sh',
|
||||
\ }
|
||||
|
||||
|
||||
" Automatically closes brackets, quotes and parentheses
|
||||
Plug 'jiangmiao/auto-pairs'
|
|
@ -40,6 +40,7 @@ set splitbelow
|
|||
|
||||
" Turn off relativenumber only for insert mode.
|
||||
if has('nvim')
|
||||
set relativenumber
|
||||
augroup every
|
||||
autocmd!
|
||||
au InsertEnter * set norelativenumber
|
|
@ -7,7 +7,7 @@ filetype on
|
|||
set runtimepath+=~/.config/vim,~/.cache/vim
|
||||
set viminfo+=n~/.cache/vim/viminfo
|
||||
|
||||
source ~/.config/vim/plugins
|
||||
source ~/.config/vim/pluginconfig
|
||||
source ~/.config/vim/vimconfig
|
||||
source ~/.config/vim/pluginlist.vim
|
||||
source ~/.config/vim/pluginconfig.vim
|
||||
source ~/.config/vim/vimconfig.vim
|
||||
|
||||
|
|
Loading…
Reference in a new issue