diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..f514c1d --- /dev/null +++ b/.editorconfig @@ -0,0 +1,2 @@ +[**/*.py] +vim_modeline = set noet ts=2 sts=2 sw=2 ai ci diff --git a/Makefile b/Makefile index e34a7fb..6e4f1fb 100644 --- a/Makefile +++ b/Makefile @@ -69,7 +69,6 @@ dotfiles_put: cp dotfiles/.vimrc ~/.vimrc cp dotfiles/.tmux.conf ~/.tmux.conf cp dotfiles/.py3.vimrc ~/.py3.vimrc - cp dotfiles/.py3.vimrc ~/.py3.vimrc cp dotfiles/.gitconfig ~/.gitconfig cp -rp \ dotfiles/.ipython/profile_default/ipython_config.py \ @@ -82,6 +81,12 @@ dotfiles_put: done #commands install -f -p dotfiles -s dotfiles/ -t ~/.config/ +dotfiles_vim_put: + mkdir -p $(INSTALL_ROOT) + + cp dotfiles/.vimrc ~/.vimrc + cp dotfiles/.py3.vimrc ~/.py3.vimrc + PLATFORM ?= macbook_air_2012 PLATFORM_TMP ?= tmp/platform_dotfiles/$(PLATFORM) diff --git a/dotfiles/.py3.vimrc b/dotfiles/.py3.vimrc index d453fab..b798dd3 100644 --- a/dotfiles/.py3.vimrc +++ b/dotfiles/.py3.vimrc @@ -1,4 +1,15 @@ py3 << EOF +from typing import (Optional, ClassVar, Self,) +import configparser +import re +import pathlib +import logging +import fnmatch + +logger = logging.getLogger(__name__) + +logging.basicConfig(level=logging.WARNING) + def f1(): t1 = vim.current.window t2 = t1.width @@ -122,8 +133,96 @@ def f5_1(pattern, flags, info): #return [{'name': 'blah', 'filename': 'docker-compose.yml', 'cmd': '23'}] return t2 + +class EditorConfigModeline: + _instance : ClassVar[Optional['EditorConfigModeline']] = None + + def __init__(self) -> None: + self.configs : dict[ + pathlib.Path, + dict[str, str], + ] = dict() + + @classmethod + def singleton(cls) -> Self: + if cls._instance is None: + cls._instance = cls() + + return cls._instance + + def load_config(self) -> Optional[dict[str, str]]: + cwd = pathlib.Path.cwd() + + if not cwd in self.configs: + config_path = cwd / '.editorconfig' + + if not config_path.exists(): + return None + + parser = configparser.ConfigParser() + parser.optionxform = str # keep case + parser.read(str(config_path)) + + config : dict[str, str] = dict() + + for section in parser.sections(): + logger.info(dict(section=section)) + + if len(section) > 0: + # pattern = section[1:-1] + pattern = section + if not parser[section].get('vim_modeline') is None: + config[pattern] = parser[section].get('vim_modeline') + self.validate_modeline(config[pattern]) + + self.configs[cwd] = config + + return self.configs[cwd] + + @classmethod + def validate_modeline(cls, modeline: str) -> None: + pattern = re.compile(r'^set(\s+(noet|sts|ts|et|ai|ci|noai|noci|sw)(\=\w)?)+$') + assert pattern.match(modeline), 'invalid modeline %s' % modeline + + @classmethod + def find_entry( + cls, + config: dict[str, str], + file_path: pathlib.Path + ) -> Optional[str]: + rel_path = file_path.relative_to(pathlib.Path.cwd()) + + for pattern, modeline in config.items(): + if fnmatch.fnmatch(str(rel_path), pattern): + return modeline + + return None + + def on_buffer(self) -> None: + config = self.load_config() + + logger.info(dict(config=config)) + + buf_name = vim.current.buffer.name + file_path = pathlib.Path(buf_name).resolve() + + entry = self.find_entry(config, file_path) + + logger.info(dict(modeline=entry)) + + vim.command('silent! {}'.format(entry)) + + # vim.command("echo '{}'".format('applied %s' % entry)) + + # raise NotImplementedError + EOF +augroup EditorConfigModeline + autocmd! + autocmd BufEnter * python3 EditorConfigModeline.singleton().on_buffer() +augroup END + function! F5(pattern, flags, info) let res = py3eval( \'f5_1(