Skip to content

Instantly share code, notes, and snippets.

@ynkdir
Created July 20, 2012 04:51
Show Gist options
  • Save ynkdir/3148767 to your computer and use it in GitHub Desktop.
Save ynkdir/3148767 to your computer and use it in GitHub Desktop.
imactivateexpr
if !exists('&imstatusfunc') || !has('gui_running')
finish
endif
" Initialize after fork and GUI focus gained to get current input context.
autocmd FocusGained * call s:Init()
let s:init = 0
function! s:Init()
if s:init
return
endif
python <<EOF
import ibus
im_bus = ibus.Bus()
im_ic = ibus.InputContext(im_bus, im_bus.current_input_contxt())
def im_is_active():
if im_ic.is_enabled():
return 1
else:
return 0
def im_enable():
im_ic.enable()
def im_disable():
im_ic.disable()
EOF
set imstatusfunc=ImStatusFunc imactivatefunc=ImActivateFunc
let s:init = 1
endfunction
function! ImStatusFunc()
return pyeval('im_is_active()')
endfunction
function! ImActivateFunc(active)
if a:active
python im_enable()
else
python im_disable()
endif
endfunction
// gcc ibusctrl.c -o ibusctrl.so -shared -fPIC `pkg-config --cflags --libs ibus-1.0 glib-2.0`
#include <dlfcn.h>
#include <glib.h>
#include <ibus.h>
static IBusBus *bus = NULL;
static IBusInputContext *ic = NULL;
int im_init(const char *selfpath)
{
gchar *path;
GDBusConnection *conn;
dlopen(selfpath, RTLD_LAZY);
ibus_init();
bus = ibus_bus_new();
if (bus == NULL)
return -1;
path = ibus_bus_current_input_context(bus);
if (path == NULL)
return -1;
conn = ibus_bus_get_connection(bus);
ic = ibus_input_context_get_input_context(path, conn);
if (ic == NULL)
return -1;
g_free(path);
return 0;
}
int im_is_enabled()
{
return ibus_input_context_is_enabled(ic) ? 1 : 0;
}
int im_enable()
{
ibus_input_context_enable(ic);
return 0;
}
int im_disable()
{
ibus_input_context_disable(ic);
return 0;
}
if !exists('&imstatusfunc') || !has('gui_running')
finish
endif
" Initialize after fork and GUI focus gained to get current input context.
autocmd FocusGained * call s:Init()
let s:libpath = expand('<sfile>:p:h') . '/ibusctrl.so'
let s:init = 0
function! s:Init()
if s:init
return
endif
call libcallnr(s:libpath, 'im_init', s:libpath)
set imstatusfunc=ImStatusFunc imactivatefunc=ImActivateFunc
let s:init = 1
endfunction
function! ImStatusFunc()
return libcallnr(s:libpath, 'im_is_enabled', 0)
endfunction
function! ImActivateFunc(active)
if a:active
call libcallnr(s:libpath, 'im_enable', 0)
else
call libcallnr(s:libpath, 'im_disable', 0)
endif
endfunction
diff -r 536aa8b0c934 runtime/doc/options.txt
--- a/runtime/doc/options.txt Wed Aug 15 17:43:31 2012 +0200
+++ b/runtime/doc/options.txt Thu Aug 16 03:00:53 2012 +0900
@@ -3971,6 +3971,25 @@
Can be overruled by using "\c" or "\C" in the pattern, see
|/ignorecase|.
+ *'imactivatefunc'* *'imaf'*
+'imactivatefunc' 'imaf' string (default "")
+ global
+ {not in Vi}
+ {only available when compiled with |+xim| and
+ |+GUI_GTK|}
+ This option specifies a function to be used to activate/inactivate
+ Input Method.
+
+ Prototype is: >
+ :function ImActivateFunc(active)
+ : if a:active
+ : ... do something
+ : else
+ : ... do something
+ : endif
+ : " return value is not used
+ :endfunction
+<
*'imactivatekey'* *'imak'*
'imactivatekey' 'imak' string (default "")
global
@@ -4067,6 +4086,23 @@
The value 0 may not work correctly with Athena and Motif with some XIM
methods. Use 'imdisable' to disable XIM then.
+ *'imstatusfunc'* *'imsf'*
+'imstatusfunc' 'imsf' string (default "")
+ global
+ {not in Vi}
+ {only available when compiled with |+xim| and
+ |+GUI_GTK|}
+ This option specifies a function to be used to get status of Input
+ Method.
+
+ Prototype is: >
+ :function ImStatusFunc()
+ : let is_active = ...do something
+ : return is_active ? 1 : 0
+ :endfunction
+<
+ NOTE: This function is invoked too often. Keep it fast.
+
*'include'* *'inc'*
'include' 'inc' string (default "^\s*#\s*include")
global or local to buffer |global-local|
diff -r 536aa8b0c934 src/eval.c
--- a/src/eval.c Wed Aug 15 17:43:31 2012 +0200
+++ b/src/eval.c Thu Aug 16 03:00:53 2012 +0900
@@ -1660,7 +1660,7 @@
}
# endif
-# if defined(FEAT_COMPL_FUNC) || defined(PROTO)
+# if defined(FEAT_GTK) || defined(FEAT_COMPL_FUNC) || defined(PROTO)
/*
* Call vimL function "func" and return the result as a number.
* Returns -1 when calling the function fails.
diff -r 536aa8b0c934 src/fileio.c
--- a/src/fileio.c Wed Aug 15 17:43:31 2012 +0200
+++ b/src/fileio.c Thu Aug 16 03:00:53 2012 +0900
@@ -9529,6 +9529,12 @@
# endif
}
+ int
+is_autocmd_blocked()
+{
+ return autocmd_blocked != 0;
+}
+
/*
* Find next autocommand pattern that matches.
*/
diff -r 536aa8b0c934 src/mbyte.c
--- a/src/mbyte.c Wed Aug 15 17:43:31 2012 +0200
+++ b/src/mbyte.c Thu Aug 16 03:00:53 2012 +0900
@@ -4390,7 +4390,7 @@
{
int was_active;
- was_active = !!im_is_active;
+ was_active = !!im_get_status();
im_is_active = (active && !p_imdisable);
if (im_is_active != was_active)
@@ -5014,46 +5014,26 @@
{
if (xic != NULL)
{
- /*
- * The third-party imhangul module (and maybe others too) ignores
- * gtk_im_context_reset() or at least doesn't reset the active state.
- * Thus sending imactivatekey would turn it off if it was on before,
- * which is clearly not what we want. Fortunately we can work around
- * that for imhangul by sending GDK_Escape, but I don't know if it
- * works with all IM modules that support an activation key :/
- *
- * An alternative approach would be to destroy the IM context and
- * recreate it. But that means loading/unloading the IM module on
- * every mode switch, which causes a quite noticeable delay even on
- * my rather fast box...
- * *
- * Moreover, there are some XIM which cannot respond to
- * im_synthesize_keypress(). we hope that they reset by
- * xim_shutdown().
- */
- if (im_activatekey_keyval != GDK_VoidSymbol && im_is_active)
- im_synthesize_keypress(GDK_Escape, 0U);
-
gtk_im_context_reset(xic);
- /*
- * HACK for Ami: This sequence of function calls makes Ami handle
- * the IM reset graciously, without breaking loads of other stuff.
- * It seems to force English mode as well, which is exactly what we
- * want because it makes the Ami status display work reliably.
- */
- gtk_im_context_set_use_preedit(xic, FALSE);
-
if (p_imdisable)
im_shutdown();
else
{
- gtk_im_context_set_use_preedit(xic, TRUE);
xim_set_focus(gui.in_focus);
- if (im_activatekey_keyval != GDK_VoidSymbol)
+ if (p_imaf[0] != NUL)
{
+ char_u *argv[1];
if (im_is_active)
+ argv[0] = "1";
+ else
+ argv[0] = "0";
+ (void)call_func_retnr(p_imaf, 1, argv, FALSE);
+ }
+ else if (im_activatekey_keyval != GDK_VoidSymbol)
+ {
+ if (im_is_active)
{
g_signal_handler_block(xic, im_commit_handler_id);
im_synthesize_keypress(im_activatekey_keyval,
@@ -5211,6 +5191,21 @@
int
im_get_status(void)
{
+ if (p_imsf[0] != NUL)
+ {
+ int is_active;
+ /* FIXME: Don't execute user function in unsafe situation. */
+ if (exiting || is_autocmd_blocked())
+ return FALSE;
+ /* FIXME: :py print 'xxx' is shown duplicate result.
+ * Use silent to avoid it. */
+ ++msg_silent;
+ is_active = call_func_retnr(p_imsf, 0, NULL, FALSE);
+ --msg_silent;
+ if (is_active == -1 || is_active == 0)
+ return FALSE;
+ return TRUE;
+ }
return im_is_active;
}
diff -r 536aa8b0c934 src/option.c
--- a/src/option.c Wed Aug 15 17:43:31 2012 +0200
+++ b/src/option.c Thu Aug 16 03:00:53 2012 +0900
@@ -1416,6 +1416,15 @@
{"ignorecase", "ic", P_BOOL|P_VI_DEF,
(char_u *)&p_ic, PV_NONE,
{(char_u *)FALSE, (char_u *)0L} SCRIPTID_INIT},
+ {"imactivatefunc","imaf",P_STRING|P_VI_DEF|P_SECURE,
+# if defined(FEAT_EVAL) && defined(FEAT_XIM) && defined(FEAT_GUI_GTK)
+ (char_u *)&p_imaf, PV_NONE,
+ {(char_u *)"", (char_u *)NULL}
+# else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)NULL, (char_u *)0L}
+# endif
+ SCRIPTID_INIT},
{"imactivatekey","imak",P_STRING|P_VI_DEF,
#if defined(FEAT_XIM) && defined(FEAT_GUI_GTK)
(char_u *)&p_imak, PV_NONE,
@@ -1458,6 +1467,15 @@
{(char_u *)B_IMODE_NONE, (char_u *)0L}
#endif
SCRIPTID_INIT},
+ {"imstatusfunc","imse",P_STRING|P_VI_DEF|P_SECURE,
+# if defined(FEAT_EVAL) && defined(FEAT_XIM) && defined(FEAT_GUI_GTK)
+ (char_u *)&p_imsf, PV_NONE,
+ {(char_u *)"", (char_u *)NULL}
+# else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)NULL, (char_u *)0L}
+# endif
+ SCRIPTID_INIT},
{"include", "inc", P_STRING|P_ALLOCED|P_VI_DEF,
#ifdef FEAT_FIND_ID
(char_u *)&p_inc, PV_INC,
diff -r 536aa8b0c934 src/option.h
--- a/src/option.h Wed Aug 15 17:43:31 2012 +0200
+++ b/src/option.h Thu Aug 16 03:00:53 2012 +0900
@@ -557,6 +557,8 @@
EXTERN int p_ic; /* 'ignorecase' */
#if defined(FEAT_XIM) && defined(FEAT_GUI_GTK)
EXTERN char_u *p_imak; /* 'imactivatekey' */
+EXTERN char_u *p_imaf; /* 'imactivatefunc' */
+EXTERN char_u *p_imsf; /* 'imstatusfunc' */
#endif
#ifdef USE_IM_CONTROL
EXTERN int p_imcmdline; /* 'imcmdline' */
diff -r 536aa8b0c934 src/proto/fileio.pro
--- a/src/proto/fileio.pro Wed Aug 15 17:43:31 2012 +0200
+++ b/src/proto/fileio.pro Thu Aug 16 03:00:53 2012 +0900
@@ -47,6 +47,7 @@
int has_insertcharpre __ARGS((void));
void block_autocmds __ARGS((void));
void unblock_autocmds __ARGS((void));
+int is_autocmd_blocked __ARGS((void));
int has_autocmd __ARGS((event_T event, char_u *sfname, buf_T *buf));
char_u *get_augroup_name __ARGS((expand_T *xp, int idx));
char_u *set_context_in_autocmd __ARGS((expand_T *xp, char_u *arg, int doautocmd));
@mattn
Copy link

mattn commented Aug 17, 2012

僕の方じゃないすかね。中平さんのは試してないだけで上手くいくのは見えてるので。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment