mirror of
https://github.com/lilydjwg/fcitx.vim.git
synced 2026-01-27 18:57:13 +08:00
a C/S version for sudo vim
This commit is contained in:
parent
695ee2b958
commit
dc9a01822d
3 changed files with 128 additions and 30 deletions
|
|
@ -1,10 +1,13 @@
|
||||||
Keep and restore fcitx state for each buffer separately when leaving/re-entering insert mode. Like always typing English in normal mode, but Chinese in insert mode.
|
Keep and restore fcitx state for each buffer separately when leaving/re-entering insert mode. Like always typing English in normal mode, but Chinese in insert mode.
|
||||||
|
|
||||||
|
The branch uses a server-client architecture to support cross-user usage (e.g. `sudo vim`) or even cross-host usages (not implemented yet).
|
||||||
|
|
||||||
Requires:
|
Requires:
|
||||||
|
|
||||||
* fcitx 5
|
* fcitx 5
|
||||||
* Vim with Python 3 compiled in
|
* Vim with Python 3 compiled in
|
||||||
* The python-dbus package
|
* The python-dbus package
|
||||||
|
* Run the `fcitx-status` script as a service
|
||||||
|
|
||||||
Links:
|
Links:
|
||||||
|
|
||||||
|
|
@ -17,11 +20,14 @@ Warning:
|
||||||
|
|
||||||
在离开或重新进入插入模式时自动记录和恢复每个缓冲区各自的输入法状态,以便在普通模式下始终是英文输入模式,切换回插入模式时恢复离开前的输入法输入模式。
|
在离开或重新进入插入模式时自动记录和恢复每个缓冲区各自的输入法状态,以便在普通模式下始终是英文输入模式,切换回插入模式时恢复离开前的输入法输入模式。
|
||||||
|
|
||||||
|
这个分支使用服务端/客户端架构,以便支持跨用户的用法(如 `sudo vim`),甚至是跨主机的用法(尚未实现)。
|
||||||
|
|
||||||
要求:
|
要求:
|
||||||
|
|
||||||
* fcitx 5
|
* fcitx 5
|
||||||
* 带有 Python 3 支持的 Vim
|
* 带有 Python 3 支持的 Vim
|
||||||
* python-dbus 包
|
* python-dbus 包
|
||||||
|
* 作为服务运行 `fcitx-status` 脚本
|
||||||
|
|
||||||
链接:
|
链接:
|
||||||
|
|
||||||
|
|
|
||||||
67
fcitx-status
Executable file
67
fcitx-status
Executable file
|
|
@ -0,0 +1,67 @@
|
||||||
|
#!/usr/bin/python3
|
||||||
|
|
||||||
|
import asyncio
|
||||||
|
import functools
|
||||||
|
|
||||||
|
import dbus
|
||||||
|
|
||||||
|
def may_reconnect(func):
|
||||||
|
@functools.wraps(func)
|
||||||
|
def wrapped(self, *args, **kwargs):
|
||||||
|
for _ in range(2):
|
||||||
|
try:
|
||||||
|
return func(self, *args, **kwargs)
|
||||||
|
except dbus.exceptions.DBusException:
|
||||||
|
self.connect()
|
||||||
|
return wrapped
|
||||||
|
|
||||||
|
class FcitxComm():
|
||||||
|
def __init__(self):
|
||||||
|
self.connect()
|
||||||
|
|
||||||
|
def connect(self):
|
||||||
|
bus = dbus.SessionBus()
|
||||||
|
obj = bus.get_object('org.fcitx.Fcitx5', '/controller')
|
||||||
|
self.fcitx = dbus.Interface(obj, dbus_interface='org.fcitx.Fcitx.Controller1')
|
||||||
|
|
||||||
|
@may_reconnect
|
||||||
|
def status(self):
|
||||||
|
return self.fcitx.State() == 2
|
||||||
|
|
||||||
|
@may_reconnect
|
||||||
|
def activate(self):
|
||||||
|
self.fcitx.Activate()
|
||||||
|
|
||||||
|
@may_reconnect
|
||||||
|
def deactivate(self):
|
||||||
|
self.fcitx.Deactivate()
|
||||||
|
|
||||||
|
async def fcitx_serve(Fcitx, reader, writer):
|
||||||
|
while True:
|
||||||
|
data = await reader.read(1)
|
||||||
|
if not data:
|
||||||
|
break
|
||||||
|
comm = data[0]
|
||||||
|
if comm == 0:
|
||||||
|
st = 1 if Fcitx.status() else 0
|
||||||
|
writer.write(st.to_bytes(1, 'little'))
|
||||||
|
await writer.drain()
|
||||||
|
elif comm == 1:
|
||||||
|
Fcitx.activate()
|
||||||
|
elif comm == 2:
|
||||||
|
Fcitx.deactivate()
|
||||||
|
|
||||||
|
async def main():
|
||||||
|
Fcitx = FcitxComm()
|
||||||
|
server = await asyncio.start_unix_server(
|
||||||
|
functools.partial(fcitx_serve, Fcitx), path='\0fcitx-status')
|
||||||
|
async with server:
|
||||||
|
await server.serve_forever()
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
try:
|
||||||
|
import setproctitle
|
||||||
|
setproctitle.setproctitle('fcitx-status')
|
||||||
|
except ImportError:
|
||||||
|
pass
|
||||||
|
asyncio.run(main())
|
||||||
|
|
@ -1,49 +1,72 @@
|
||||||
import vim
|
import vim
|
||||||
import functools
|
import socket
|
||||||
|
import struct
|
||||||
|
|
||||||
import dbus
|
fcitxsocketfile = '\0fcitx-status'
|
||||||
|
fcitx_loaded = False
|
||||||
|
|
||||||
class FcitxComm():
|
class FcitxComm(object):
|
||||||
def __init__(self):
|
STATUS = b'\0'
|
||||||
bus = dbus.SessionBus()
|
ACTIVATE = b'\1'
|
||||||
obj = bus.get_object('org.fcitx.Fcitx5', '/controller')
|
DEACTIVATE = b'\2'
|
||||||
self.fcitx = dbus.Interface(obj, dbus_interface='org.fcitx.Fcitx.Controller1')
|
|
||||||
|
def __init__(self, socketfile):
|
||||||
|
self.socketfile = socketfile
|
||||||
|
self.sock = None
|
||||||
|
|
||||||
def status(self):
|
def status(self):
|
||||||
return self.fcitx.State() == 2
|
return self._with_socket(self._status)
|
||||||
|
|
||||||
def activate(self):
|
def activate(self):
|
||||||
self.fcitx.Activate()
|
self._with_socket(self._command, self.ACTIVATE)
|
||||||
|
|
||||||
def deactivate(self):
|
def deactivate(self):
|
||||||
self.fcitx.Deactivate()
|
self._with_socket(self._command, self.DEACTIVATE)
|
||||||
|
|
||||||
try:
|
def _error(self, e):
|
||||||
Fcitx = FcitxComm()
|
estr = str(e).replace('"', r'\"')
|
||||||
fcitx_loaded = True
|
file = self.socketfile.replace('"', r'\"').replace('\0', '@')
|
||||||
except dbus.exceptions.DBusException as e:
|
vim.command('echohl WarningMsg | echo "fcitx.vim: socket %s error: %s" | echohl NONE' % (file, estr))
|
||||||
vim.command('echohl WarningMsg | echom "fcitx.vim not loaded: %s" | echohl NONE' % e)
|
|
||||||
fcitx_loaded = False
|
|
||||||
|
|
||||||
def may_reconnect(func):
|
def _connect(self):
|
||||||
@functools.wraps(func)
|
self.sock = sock = socket.socket(socket.AF_UNIX)
|
||||||
def wrapped():
|
sock.settimeout(0.5)
|
||||||
global Fcitx
|
try:
|
||||||
for _ in range(2):
|
sock.connect(self.socketfile)
|
||||||
try:
|
return True
|
||||||
return func()
|
except (socket.error, socket.timeout) as e:
|
||||||
except Exception as e:
|
self.sock = None
|
||||||
vim.command('echohl WarningMsg | echom "fcitx.vim: %s: %s" | echohl NONE' % (type(e).__name__, e))
|
self._error(e)
|
||||||
Fcitx = FcitxComm()
|
return False
|
||||||
return wrapped
|
|
||||||
|
def _with_socket(self, func, *args, **kwargs):
|
||||||
|
if not self.sock:
|
||||||
|
if not self._connect():
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
return func(*args, **kwargs)
|
||||||
|
except (socket.error, socket.timeout, struct.error) as e:
|
||||||
|
self._error(e)
|
||||||
|
|
||||||
|
def _status(self):
|
||||||
|
self.sock.send(self.STATUS)
|
||||||
|
return self.sock.recv(1)[0]
|
||||||
|
|
||||||
|
def _command(self, cmd):
|
||||||
|
self.sock.send(cmd)
|
||||||
|
|
||||||
|
Fcitx = FcitxComm(fcitxsocketfile)
|
||||||
|
|
||||||
@may_reconnect
|
|
||||||
def fcitx2en():
|
def fcitx2en():
|
||||||
if Fcitx.status():
|
st = Fcitx.status()
|
||||||
|
if st is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
if st:
|
||||||
vim.command('let b:inputtoggle = 1')
|
vim.command('let b:inputtoggle = 1')
|
||||||
Fcitx.deactivate()
|
Fcitx.deactivate()
|
||||||
|
|
||||||
@may_reconnect
|
|
||||||
def fcitx2zh():
|
def fcitx2zh():
|
||||||
if vim.eval('exists("b:inputtoggle")') == '1':
|
if vim.eval('exists("b:inputtoggle")') == '1':
|
||||||
if vim.eval('b:inputtoggle') == '1':
|
if vim.eval('b:inputtoggle') == '1':
|
||||||
|
|
@ -51,3 +74,5 @@ def fcitx2zh():
|
||||||
vim.command('let b:inputtoggle = 0')
|
vim.command('let b:inputtoggle = 0')
|
||||||
else:
|
else:
|
||||||
vim.command('let b:inputtoggle = 0')
|
vim.command('let b:inputtoggle = 0')
|
||||||
|
|
||||||
|
fcitx_loaded = True
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue