[+] update vim config

1. add dynamic modeline
    application
    based on .editorconfig,
    vim_modeline key;
    with validation for security;
This commit is contained in:
Siarhei Siniak 2025-10-10 13:26:32 +03:00
parent 01e98958a6
commit 81f3fc494a
3 changed files with 107 additions and 1 deletions

2
.editorconfig Normal file

@ -0,0 +1,2 @@
[**/*.py]
vim_modeline = set noet ts=2 sts=2 sw=2 ai ci

@ -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)

@ -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(