hchunhui / librime-lua

Extending RIME with Lua scripts
BSD 3-Clause "New" or "Revised" License
310 stars 43 forks source link

动态更改menu/page_size时,调用apply_schema报错 #204

Open AlienKevin opened 2 years ago

AlienKevin commented 2 years ago

我在开发一个韩文输入法,目标是平常输入韩文的时候不显示menu (page_size = 0),menu只在反查汉字的时候显示。基于PR135,我写了一个简单版本的processor,当按下F10键时会改变朙月拼音的page_size。不过env.engine.apply_schema报错说attempt to call a nil value (field 'apply_schema'),env.engine:apply_schema也有类似报错。

报错message:

E0930 14:06:07.148494 44123520 lua_gears.cc:150] LuaProcessor::ProcessKeyEvent error(2): /Users/kevin/Library/Rime/lua/page_size_processor.lua:20: attempt to call a nil value (field 'apply_schema')

processor代码如下:

local function init(env)
  log.info("===================== init page_size_processor =====================")
end

local function processor(key,env)
  log.info("-------------- start of page_size_processor --------------")
  local Rejected,Accepted,Noop=0,1,2
  local config=env.engine.schema.config
  if key:repr() == "F10" then
    config:set_int("menu/page_size", 10)
    -- reload schema to activate config
    env.engine.apply_schema(env.engine.schema.schema_id)
    return Accepted
  end 
  return Noop
end

local function fini(env)
  print("===================== fini page_size_processor =====================")
end

return { init = init, func = processor, fini = fini }

版本

squirrel master branch最新commit

LawssssCat commented 2 years ago

报错含义就是 Engine 里面没有 apply_schema 方法。 大概因为 librime-lua 插件不是最新的?

AlienKevin commented 2 years ago

感谢答复,我是今天用东风破安装的librime-lua,不确定东风破安装的是不是最新版?我手动检查了位于package/hchunhui/librime-lua/src/types.cc文件,发现里面有apply_schema的定义:

  static void apply_schema(T *engine, the<Schema> &schema) {
    engine->ApplySchema(schema.release());
  }
shewer commented 2 years ago

用 engine:apply_schema( env.engine.schema) 很容易 出問題的 commit: 日 schema: cangjie5 / 倉頡五代 status: (not composing) {F9} double free or corruption (out) -- [1] 1065960 IOT instruction (core dumped) ./rime_api_console

查詢一下 isuue 有個 檢查 librime-lua 版本的function

Rime fcitx-rime 5.0.14 (id:f802202b-a976-4d1a-b171-7fba1e1d29f4) Ver: librime 1.7.3 librime-lua 185 lua Lua 5.4

AlienKevin commented 2 years ago

我运行了检查版本的log,结果报错:

E0930 20:13:41.337082 44123520 lua_gears.cc:44] Lua error:(2): /Users/kevin/Library/Rime/lua/page_size_processor.lua:3: attempt to call a nil value (field 'get_distribution_name')

这是我的版本打印程序:

local function init(env)
  log.info("===================== init page_size_processor =====================")
  log.info(rime_api.get_distribution_name())
  log.info(rime_api.get_distribution_version())
  log.info(rime_api.get_distribution_code_name())
  log.info(rime_api.get_user_id())
end

我使用的是macOS Monterey (M1),今天新装了squirrel的最新commit,会不会造成报错?我发现新版本的squirrel会在系统输入法那里注册简体和繁体两个选项。我可以试试删除新版本的squirrel然后在老版本从新测试。

我本机之前从来没有装过lua,不过这样能排除lua版本的问题吗?

Update: 我退到稳定版本的squirrel后有同样的版本报错。

shewer commented 2 years ago

把產生出來的 string 看是要作成 lua_translator 中的字典 或是 lua_processor 的 commit_text

-- processor
function proc.func(key,env)
   ......
    if  context.input == "/ver" or key:eq("EventKey('F12") ) then
        context:clear() 
        env.engine:commit_text(  ver func)
        return Accepted -- 1
    end
 end
-- lua_translator
 function tran.func(inp,seg,env)
    if inp== "/ver" then
       yield( Candidate("ver", seg.start, seg._end, Ver_info() , ""))
    end
end
function Version()
  local ver
  if rime_api.get_distribution_name then
    return 185
  elseif LevelDb then
    return 177
  elseif Opencc then
    return 147
  elseif KeySequence and KeySequence().repr then
    return 139
  elseif  ConfigMap and ConfigMap().keys then
    return 127
  elseif Projection then
    return 102
  elseif KeyEvent then
    return 100
  elseif Memory then
    return 80
  elseif rime_api.get_user_data_dir then
    return 9
  elseif log then
    return 9
  else
    return 0
  end
end
function Ver_info()
  local msg1 = rime_api.get_user_id and string.format(" %s %s %s (id:%s) ",
  rime_api.get_distribution_name(),
  rime_api.get_distribution_code_name(),
  rime_api.get_distribution_version(),
  rime_api.get_user_id()) or ""

  local msg2 = string.format(" Ver: librime %s librime-lua %s lua %s",
  rime_api.get_rime_version() , Version() ,_VERSION )
  return msg1 .. msg2
end
AlienKevin commented 2 years ago

感谢🙏,我把你的script放到了rime.lua里面,然后luna_pinyin.schema.yaml里面加了两行调用processor和translator。

成功获取了版本号! Ver: librime 1.7.3 librime-lua 9 lua Lua 5.4

shewer commented 2 years ago

調換一下順序 ( proc tran 擇一即可 ) Version() Ver_info() -- call Version

module function -- call Ver_info() https://github.com/hchunhui/librime-lua/suites/8448091896/artifacts/374612908

195 版本 for osx win10

AlienKevin commented 2 years ago

问题1:这个是我改过之后的rime.lua,我把Ver_info放到了Version前面。想确认一下调换顺序就是指把Version和Ver_info两个函数的位置调换吗?

rime.lua ```lua -- processor function version_processor(key,env) local Rejected,Accepted,Noop=0,1,2 if context.input == "/ver" or key:eq("EventKey('F12") then context:clear() env.engine:commit_text(Ver_info()) return Accepted -- 1 end end -- lua_translator function version_translator(inp,seg,env) if inp == "/ver" then yield(Candidate("ver", seg.start, seg._end, Ver_info() , "")) end end function Ver_info() local msg1 = rime_api.get_user_id and string.format(" %s %s %s (id:%s) ", rime_api.get_distribution_name(), rime_api.get_distribution_code_name(), rime_api.get_distribution_version(), rime_api.get_user_id()) or "" local msg2 = string.format(" Ver: librime %s librime-lua %s lua %s", rime_api.get_rime_version() , Version() ,_VERSION ) return msg1 .. msg2 end function Version() local ver if rime_api.get_distribution_name then return 185 elseif LevelDb then return 177 elseif Opencc then return 147 elseif KeySequence and KeySequence().repr then return 139 elseif ConfigMap and ConfigMap().keys then return 127 elseif Projection then return 102 elseif KeyEvent then return 100 elseif Memory then return 80 elseif rime_api.get_user_data_dir then return 9 elseif log then return 9 else return 0 end end ```

问题2: 直接用你发的版本来代替Squirrel.app/Content里面的这三个executable就可以了吗?其他的executable会不会出现不兼容现象?

Screen Shot 2022-09-30 at 10 07 04 PM
shewer commented 2 years ago

不曉得 , window 是這樣的 ,把 rime.dll 替換即可

AlienKevin commented 2 years ago

Ok, 我查了下dylib在macOS和dll等同。我尝试用你的librime.1.dylib替换了我的,不过architecture不吻合,所以Squirrel报错: Library not loaded: '@rpath/librime.1.dylib' ... mach-o file, but is an incompatible architecture (have (x86_64), need (arm64e)))

有什么办法我可以自己build librime或者哪里可以找到arm版的build?

UPDATE: 我看到你发的版本里面librime是1.7.3,这和我之前用的版本一致,可能问题不在librime?

AlienKevin commented 2 years ago

我从librime github release那里下载了librime 1.7.3然后放到了Squirrel里面,现在出现了新的报错:

E0930 22:54:10.376711 14419328 engine.cc:312] error creating processor: 'lua_processor'
E0930 22:54:10.377452 14419328 engine.cc:346] error creating translator: 'lua_translator'
shewer commented 2 years ago

我目前用的都是最新的 librime + librime-lua 其他 plugin bsd (osx) and linux 自行編譯應該蠻容易的

git clone https://github.com/rime/librime
cd librime
#   clone  to  ./plugins/
./install-plugin.sh hchunhui/librime-lua
./install-plugins.sh rime/librime-charcode
./install-plugins.sh lotem/librime-octagram
./install-plugins.sh lotem/librime-proto

mkdir  build && cd build 
cmake .. && cmake --build  .   
shewer commented 2 years ago

我从librime github release那里下载了librime 1.7.3然后放到了Squirrel里面,现在出现了新的报错:

E0930 22:54:10.376711 14419328 engine.cc:312] error creating processor: 'lua_processor'
E0930 22:54:10.377452 14419328 engine.cc:346] error creating translator: 'lua_translator'

沒有 plugins librime-lua

AlienKevin commented 2 years ago

好的🙏,我大概明白了,一会儿试试看

AlienKevin commented 2 years ago

终于build好了!Version输出185应该没问题了。不过env.engine.apply_schema(env.engine.schema.schema_id)这一行直接把preedit里面的东西删了,然后候选字数没有变化,而且似乎还把我的squirrel factory reset了(皮肤和自己下载的输入法插件都没了)。我尝试重新sync user data然后deploy,但是任然无法将任何设置恢复,只有log out然后重新登录才能恢复。请问有什么安全有效的方法去改变menu/page_size?或者可以让translator不添加candidate,但是按空格仍然可以lookup词典输出正确的词。

shewer commented 2 years ago

我查了 librime source 關於 page_size 都是參照 sechema.page_size() 簡單的方式是 scheam.h 增加 set_page_size(int) & types.cc SchemaReg::vars_set[] 增加 page_size; 是 可行的且穩定 ,你`可以試試 https://github.com/rime/librime/pull/572 不知道這PR是否會通過

//librime/src/rime/schema.h
class Schema{
    void set_page_size(int page_size) { page_size_ = page_size; }
}
//-----
//plugins/lua/src/types.cc
SchemaReg
   luaL_Reg vars_set[]{
      {"page_size" , WRAPMEM(T::set_page_size)},   // <<---- added
}

reload 自身方案 容易出現 memory 錯誤( engine:apply_schema( Schema) : 別的 方案OK )

AlienKevin commented 2 years ago

这个方法好,我试试看

AlienKevin commented 2 years ago

fork了librime-lua然后加上了你上面提到的那一行到types.cc。之后,我用你的patch-1分支,plugin-install了我的fork版本的librime-lua,然后编译librime成功。不过,当我替换了Squirrel里面的librime.dylib文件,并且重启Squirrel后,在启动时报错:

kevin@Kevins-MacBook-Pro T % /Library/Input\ Methods/Squirrel.app/Contents/MacOS/Squirrel --quit; /Library/Input\ Methods/Squirrel.app/Contents/MacOS/Squirrel
2022-10-01 22:17:09.876 Squirrel[90815:955332] Initializing la rime...
2022-10-01 22:17:09.883 Squirrel[90815:955332] Squirrel reporting!
2022-10-01 22:17:11.561 Squirrel[90815:955332] createSession: com.apple.Spotlight
2022-10-01 22:17:11.843 Squirrel[90815:955332] set app option: ascii_mode = 1
zsh: segmentation fault  /Library/Input\ Methods/Squirrel.app/Contents/MacOS/Squirrel

当我切换回原先build的librime.dylib,Squirrel又可以正常运行。

shewer commented 2 years ago

RimeSetPageSize 是給前端用的,應該不影響 我在 rime_api_console 運作正常 還有 page_size 設定 0 會錯誤 跳離app 預設是 5

AlienKevin commented 2 years ago

明白了,那有什么办法可以隐藏候选字?

oniondelta commented 2 years ago

這邊有個思路,無奈功力不夠,lua 寫不出來 這邊韓文使用 2set 鍵位

放棄用express_editor,使用 fluency_editor,使得有半上屏狀態,會有完全隱藏候選項的時候, 再靠 lua 每打一個字母都 confirm 一次,只是這樣只有單音,還需修正XD

engine:
  processors:
    - fluency_editor

以下還待改善,目前只有單音,無法組字 思路是:如果可以把游標弄到起始位,再回復到末位,再 context:confirm_current_selection(),可能就可以組字?! shift+[QWERTOP] 目前也有問題 另外還須 if 去避掉快捷鍵等因素干擾

local function isintable(value,tb)
  for k,v in pairs(tb) do
    if v == value then
    return true
    end
  end
  return false
end

local function kr1_p(key, env)
  local engine = env.engine
  local context = engine.context
  local arr = {"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z" , "Q", "W", "E", "R", "T" ,"O" ,"P"}
  if (isintable(key:repr(),arr)) then
      context.input = context.input .. key:repr()
      key.keycode = 0
      context:confirm_current_selection()
      return 1 -- kAccepted
  end
  return 2 -- kNoop
end
shewer commented 2 years ago

這邊有個思路,無奈功力不夠,lua 寫不出來 這邊韓文使用 2set 鍵位

放棄用express_editor,使用 fluency_editor,使得有半上屏狀態,會有完全隱藏候選項的時候, 再靠 lua 每打一個字母都 confirm 一次,只是這樣只有單音,還需修正XD

engine:
  processors:
    - fluency_editor

以下還待改善,目前只有單音,無法組字 思路是:如果可以把游標弄到起始位,再回復到末位,再 context:confirm_current_selection(),可能就可以組字?! shift+[QWERTOP] 目前也有問題 另外還須 if 去避掉快捷鍵等因素干擾

local function isintable(value,tb)
  for k,v in pairs(tb) do
    if v == value then
    return true
    end
  end
  return false
end

local function kr1_p(key, env)
  local engine = env.engine
  local context = engine.context
  local arr = {"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z" , "Q", "W", "E", "R", "T" ,"O" ,"P"}
  if (isintable(key:repr(),arr)) then
      context.input = context.input .. key:repr()
      key.keycode = 0
      context:confirm_current_selection()
      return 1 -- kAccepted
  end
  return 2 -- kNoop
end
local set_char=Set {"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z" , "Q", "W", "E", "R", "T" ,"O" ,"P"} --> {a=true,b=true...}
function proc.func(key,env)
  local context = env.engine.context
  if set_char[key:repr()] then
     context.input:push( key:repr()) 
     context:confirm_current_selection()
     return 1
  end
  return 2
end
-- test
function test(func,msg, time)
  local t1=os.clock()
  for i=1,time do  func() end
  print(msg,os.clock() - t1)
end

function Set(tab)
   local rtab = {}
   for i,v in ipairs(tab) do  rtab[v]=true  end
   return rtab
end
 ktab={"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z" , "Q", "W", "E", "R", "T" ,"O" ,"P"}
key= Set(ktab)

function t1()
   local tab = Set{"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z" , "Q", "W", "E", "R", "T" ,"O" ,"P"}
   return tab['p']
end

function t2()
   return key['p']
end

function t3()
  return ('p'):match('^[a-zQWERTOP]$') and true
end

function chk(chr, tab)
   for i,v in ipairs(tab) do 
     if chr == v then return true end
   end
end

function t4()
  local  ktab={"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z" , "Q", "W", "E", "R", "T" ,"O" ,"P"}
   return chk('p', ktab)
end

function t5()
  return chk('p',ktab)
end

n=10000
test(t1,'init Set in t1 func', n)
test(t2, 'init Set out of t2 func ', n)
test(t3, ' string.match ',n)
test(t4, ' loop chk, init arr in func' , n)
test(t5, ' loop chk  init arr out of func' ,n )

init Set in t1 func 0.058258 init Set out of t2 func 0.00049999999999994 --- best string.match 0.001692 loop chk, init arr in func 0.014537 loop chk init arr out of func 0.0089570000000001

shewer commented 2 years ago

這邊有個思路,無奈功力不夠,lua 寫不出來 這邊韓文使用 2set 鍵位

放棄用express_editor,使用 fluency_editor,使得有半上屏狀態,會有完全隱藏候選項的時候, 再靠 lua 每打一個字母都 confirm 一次,只是這樣只有單音,還需修正XD

以下還待改善,目前只有單音,無法組字 思路是:如果可以把游標弄到起始位,再回復到末位,再 context:confirm_current_selection(),可能就可以組字?! shift+[QWERTOP] 目前也有問題 另外還須 if 去避掉快捷鍵等因素干擾

覺得象是 segment 的工作

oniondelta commented 2 years ago

@ shewer 感謝😄 好像是,沒碰過 librime-lua 的 segment 功能,感覺有得研究了!

AlienKevin commented 2 years ago

我写了一个lua translator可以不用词典转换韩文,不过问题是我要把转换好的结果加到一个Candidate里面,所以输入的时候一直会有一个候选字在底下。如果不是完美主义的话问题不大。

韩文我是基于rime-hangyl做的,用的是HNC Romaja,加了一点小改动:f键aliased to ᆼ,double consonant只支持大写字母,如G -> ᆩ,不支持gg。

hanul_translator.lua ```lua local function wrapped_gsub(inp, pattern, repl) inp = string.gsub(inp, "([aeiouw])" .. pattern .. "$", "%1" .. repl) inp = string.gsub(inp, "([aeiouw])" .. pattern .. "([^aeiouw])", "%1" .. repl .."%2") return inp end local function rightbound_gsub(inp, pattern, repl) inp = string.gsub(inp, pattern .. "$", repl) inp = string.gsub(inp, pattern .. "'", repl .. "'") inp = string.gsub(inp, pattern .. "([^aeiouw])", repl .. "%1") return inp end local function ascii_to_jamo(inp) log.info(inp) if inp == "" then return "" end inp = string.gsub(inp, " ", "'") inp = string.gsub(inp, "wa", "oa") inp = string.gsub(inp, "w[eo]", "ue") inp = string.gsub(inp, "f", "x") inp = string.gsub(inp, "r", "l") -- double final consonants inp = wrapped_gsub(inp,"gs", "ᆪ") inp = wrapped_gsub(inp, "nj", "ᆬ") inp = wrapped_gsub(inp, "nh", "ᆭ") inp = wrapped_gsub(inp, "lg", "ᆰ") inp = wrapped_gsub(inp, "lm", "ᆱ") inp = wrapped_gsub(inp, "lb", "ᆲ") inp = wrapped_gsub(inp, "ls", "ᆳ") inp = wrapped_gsub(inp, "lt", "ᆴ") inp = wrapped_gsub(inp, "lp", "ᆵ") inp = wrapped_gsub(inp, "lh", "ᆶ") inp = wrapped_gsub(inp, "bs", "ᆹ") -- tense and lax consonant pairs inp = rightbound_gsub(inp, "G", "ᆩ") inp = string.gsub(inp, "G", "ᄁ") inp = wrapped_gsub(inp, "g", "ᆨ") inp = string.gsub(inp, "g", "ᄀ") inp = rightbound_gsub(inp, "S", "ᆻ") inp = string.gsub(inp, "S", "ᄊ") inp = wrapped_gsub(inp, "s", "ᆺ") inp = string.gsub(inp, "s", "ᄉ") inp = string.gsub(inp, "B", "ᄈ") inp = wrapped_gsub(inp, "b", "ᆸ") inp = string.gsub(inp, "b", "ᄇ") inp = string.gsub(inp, "D", "ᄄ") inp = wrapped_gsub(inp, "d", "ᆮ") inp = string.gsub(inp, "d", "ᄃ") inp = string.gsub(inp, "J", "ᄍ") inp = wrapped_gsub(inp, "j", "ᆽ") inp = string.gsub(inp, "j", "ᄌ") -- Rest of the consonants inp = wrapped_gsub(inp, "l", "ᆯ") inp = string.gsub(inp, "l", "ᄅ") inp = wrapped_gsub(inp, "m", "ᆷ") inp = string.gsub(inp, "m", "ᄆ") inp = wrapped_gsub(inp, "h", "ᇂ") inp = string.gsub(inp, "h", "ᄒ") inp = wrapped_gsub(inp, "n", "ᆫ") inp = string.gsub(inp, "n", "ᄂ") inp = wrapped_gsub(inp, "c", "ᆾ") inp = string.gsub(inp, "c", "ᄎ") inp = wrapped_gsub(inp, "p", "ᇁ") inp = string.gsub(inp, "p", "ᄑ") inp = wrapped_gsub(inp, "t", "ᇀ") inp = string.gsub(inp, "t", "ᄐ") inp = wrapped_gsub(inp, "k", "ᆿ") inp = string.gsub(inp, "k", "ᄏ") inp = string.gsub(inp, "([^aeiouw])x", "%1ᄋ") inp = string.gsub(inp, "x([aeiouw])", "ᄋ%1") inp = string.gsub(inp, "x", "ᆼ") inp = string.gsub(inp, "iai", "ᅤ") inp = string.gsub(inp, "iei", "ᅨ") inp = string.gsub(inp, "uei", "ᅰ") inp = string.gsub(inp, "oai", "ᅫ") inp = string.gsub(inp, "ai", "ᅢ") inp = string.gsub(inp, "ei", "ᅦ") inp = string.gsub(inp, "ia", "ᅣ") inp = string.gsub(inp, "ie", "ᅧ") inp = string.gsub(inp, "io", "ᅭ") inp = string.gsub(inp, "iu", "ᅲ") inp = string.gsub(inp, "ue", "ᅯ") inp = string.gsub(inp, "ui", "ᅱ") inp = string.gsub(inp, "wi", "ᅴ") inp = string.gsub(inp, "oa", "ᅪ") inp = string.gsub(inp, "o", "ᅩ") inp = string.gsub(inp, "e", "ᅥ") inp = string.gsub(inp, "a", "ᅡ") inp = string.gsub(inp, "i", "ᅵ") inp = string.gsub(inp, "u", "ᅮ") inp = string.gsub(inp, "w", "ᅳ") inp = string.gsub(inp, "'", "") log.info(inp) return inp end -- assumes inp has only a single Unicode character local function is_lpart_jamo(c) return 0x1100 <= c and c <= 0x1112 end -- assumes inp has only a single Unicode character local function is_vpart_jamo(c) return 0x1161 <= c and c <= 0x1175 end -- assumes inp has only a single Unicode character local function is_tpart_jamo(c) return 0x11A8 <= c and c <= 0x11C2 end local function jamos_to_hangul(inp) local SBase = 0xAC00 local LBase = 0x1100 local VBase = 0x1161 local TBase = 0x11A7 local LCount = 19 local VCount = 21 local TCount = 28 local NCount = 588 -- VCount * TCount local SCount = 11172 -- LCount * NCount local l_state = 0 local v_state = 1 local t_state = 2 local part_state = l_state local LVIndex = 0 local hangul = "" for _, part in utf8.codes(inp) do print(part) if part_state == l_state then -- lpart state if is_lpart_jamo(part) then LVIndex = (part - LBase) * NCount part_state = v_state else hangul = hangul .. utf8.char(part) end elseif part_state == v_state then -- vpart state if is_vpart_jamo(part) then LVIndex = LVIndex + (part - VBase) * TCount part_state = t_state else prev_lpart = LVIndex // NCount + LBase if is_lpart_jamo(part) then hangul = hangul .. utf8.char(prev_lpart) LVIndex = (part - LBase) * NCount else hangul = hangul .. utf8.char(prev_lpart, part) part_state = l_state end end elseif part_state == t_state then -- tpart state local s = 0 local append_hangul = "" if is_tpart_jamo(part) then TIndex = part - TBase s = SBase + LVIndex + TIndex part_state = l_state elseif is_lpart_jamo(part) then s = SBase + LVIndex LVIndex = (part - LBase) * NCount part_state = v_state else s = SBase + LVIndex append_hangul = utf8.char(part) part_state = l_state end print(s) hangul = hangul .. utf8.char(s) .. append_hangul end end if part_state == v_state then prev_lpart = LVIndex // NCount + LBase hangul = hangul .. utf8.char(prev_lpart) elseif part_state == t_state then s = SBase + LVIndex hangul = hangul .. utf8.char(s) end return hangul end local function translator(inp, seg) local hangul = jamos_to_hangul(ascii_to_jamo(inp)) local cand = Candidate("placeholder", seg.start, seg._end, hangul, "") cand.preedit = hangul yield(cand) end return translator ```
hnc_romaja_mod.schema.yaml ```yaml # Rime schema # vim: set sw=2 sts=2 et: # encoding: utf-8 schema: schema_id: hnc_romaja_mod name: HNC Romaja (mod) version: "0.1" author: - Kevin Li - Patrick - 雪齋 description: | HNC Romaja for Rime (This is a slightly modified version where f is mapped to ㅇ for convenience) ㄱg ㄴn ㄷd ㄹl/r ㅁm ㅂb ㅅs ㅇx/f ㅈj ㅊc ㅋk ㅌt ㅍp ㅎh ㅏaㅐai ㅑia ㅒiai ㅓe ㅔei ㅕie ㅖiei ㅗo ㅘoa ㅙoai ㅚoi ㅛio ㅜu ㅝue ㅞuei ㅟui ㅠiu ㅡw ㅢwi ㅣi/y dependencies: - hnc_hanja_mod # menu: # page_size: 0 switches: - name: half_shape states: [ 半角, 全角 ] reset: 0 engine: processors: - ascii_composer - recognizer - key_binder - speller - punctuator - selector - navigator - express_editor # - fluency_editor segmentors: - ascii_segmentor - matcher - affix_segmentor@hnc_hanja_mod - abc_segmentor - punct_segmentor - fallback_segmentor translators: - punct_translator - script_translator - script_translator@hnc_hanja_mod - echo_translator - lua_translator@hangul_translator filters: - simplifier - uniquifier - reverse_lookup_filter@romaja_reverse_lookup speller: alphabet: 'zyxwvutsrqponmlkjihgfedcbaBDGSJ' initials: 'zyxwvutsrqponmlkjihgfedcbaBDGSJ' finals: 'zyxwvutsrqponmlkjihgfedcbaGS' delimiter: " '" algebra: # - abbrev/^([gndlmbsqjcktph]).+$/$1/ # - derive/(^|[ '])x?([aeiouy])/$1$2/ # - derive/([^aeiou]|^)B/$1bb/ - derive/'// # - derive/x$/ng/ - derive/x/f/ - derive/l/r/ # - derive/p/f/ - derive/i/y/ - derive/oa/wa/ - derive/ue/we/ - derive/ue/wo/ - derive/i([aeou])/y$1/ - derive/^([A-Za-z]+)\d$/$1/ hnc_hanja_mod: tag: hnc_hanja_mod dictionary: hnc_hanja_mod prefix: "`" suffix: ";" # enable_completion: true # overwrite_comment: false tips: 〔漢字・한자〕 preedit_format: - xform/ /'/ - xform/wa/oa/ - xform/w[eo]/ue/ - xform/f/x/ - xform/r/l/ # double final consonants - xform/([aeiouw])gs($|'|[^aeiouw])/$1ᆪ$2/ - xform/([aeiouw])nj($|'|[^aeiouw])/$1ᆬ$2/ - xform/([aeiouw])nh($|'|[^aeiouw])/$1ᆭ$2/ - xform/([aeiouw])lg($|'|[^aeiouw])/$1ᆰ$2/ - xform/([aeiouw])lm($|'|[^aeiouw])/$1ᆱ$2/ - xform/([aeiouw])lb($|'|[^aeiouw])/$1ᆲ$2/ - xform/([aeiouw])ls($|'|[^aeiouw])/$1ᆳ$2/ - xform/([aeiouw])lt($|'|[^aeiouw])/$1ᆴ$2/ - xform/([aeiouw])lp($|'|[^aeiouw])/$1ᆵ$2/ - xform/([aeiouw])lh($|'|[^aeiouw])/$1ᆶ$2/ - xform/([aeiouw])bs($|'|[^aeiouw])/$1ᆹ$2/ # tense and lax consonant pairs - xform/G($|')/ᆩ$1/ - xform/G/ᄁ/ - xform/([aeiouw])g($|'|[^aeiouw])/$1ᆨ$2/ - xform/g/ᄀ/ - xform/S($|')/ᆻ$1/ - xform/S/ᄊ/ - xform/([aeiouw])s($|'|[^aeiouw])/$1ᆺ$2/ - xform/s/ᄉ/ # - derive/([^aeiou]|^)bb/$1B/ - xform/B/ᄈ/ - xform/([aeiouw])b($|'|[^aeiouw])/$1ᆸ$2/ - xform/b/ᄇ/ - xform/D/ᄄ/ - xform/([aeiouw])d($|'|[^aeiouw])/$1ᆮ$2/ - xform/d/ᄃ/ - xform/J/ᄍ/ - xform/([aeiouw])j($|'|[^aeiouw])/$1ᆽ$2/ - xform/j/ᄌ/ # Rest of the consonants - xform/([aeiouw])l($|'|[^aeiouw])/$1ᆯ$2/ - xform/l/ᄅ/ - xform/([aeiouw])m($|'|[^aeiouw])/$1ᆷ$2/ - xform/m/ᄆ/ - xform/([aeiouw])h($|'|[^aeiouw])/$1ᇂ$2/ - xform/h/ᄒ/ - xform/([aeiouw])n($|'|[^aeiouw])/$1ᆫ$2/ - xform/n/ᄂ/ - xform/([aeiouw])c($|'|[^aeiouw])/$1ᆾ$2/ - xform/c/ᄎ/ - xform/([aeiouw])p($|'|[^aeiouw])/$1ᇁ$2/ - xform/p/ᄑ/ - xform/([aeiouw])t($|'|[^aeiouw])/$1ᇀ$2/ - xform/t/ᄐ/ - xform/([aeiouw])k($|'|[^aeiouw])/$1ᆿ$2/ - xform/k/ᄏ/ - xform/iai/ᅤ/ - xform/iei/ᅨ/ - xform/uei/ᅰ/ - xform/oai/ᅫ/ - xform/ai/ᅢ/ - xform/ei/ᅦ/ - xform/ia/ᅣ/ - xform/ie/ᅧ/ - xform/io/ᅭ/ - xform/iu/ᅲ/ - xform/ue/ᅯ/ - xform/ui/ᅱ/ - xform/wi/ᅴ/ - xform/oa/ᅪ/ - xform/o/ᅩ/ - xform/e/ᅥ/ - xform/a/ᅡ/ - xform/i/ᅵ/ - xform/u/ᅮ/ - xform/w/ᅳ/ - xform/(^|'|`)x/ᄋ/ - xform/x/ᆼ/ - xform/'// comment_format: - xform/(^|[ '])x/$1/ - xform/x/ng/ punctuator: import_preset: default full_shape: "$" : [ ₩, ¥, "$", "€", "£", "¥", "¢", "¤" ] half_shape: "$" : [ ₩, "$", "€", "£", "¥", "¢", "¤" ] "," : { commit: "," } "." : { commit: "." } "<" : "<" ">" : ">" "/" : "/" "?" : { commit: "?" } ";" : { commit: ";" } ":" : { commit: ":" } "'" : "'" "\"" : "\"" "\\" : "\\" "|" : "|" "`" : "`" "~" : "~" "!" : { commit: "!" } "@" : "@" "#" : "#" "%" : "%" "^" : "^" "&" : "&" "*" : "*" "(" : "(" ")" : ")" "-" : "-" "_" : "_" "+" : "+" "=" : "=" "[" : "[" "]" : "]" "{" : "{" "}" : "}" key_binder: import_preset: default recognizer: import_preset: default patterns: hnc_hanja_mod: "^`[a-zA-Z']*;?$" romaja_reverse_lookup: tags: [ hnc_hanja_mod ] overwrite_comment: false dictionary: hnc_romaja_mod ```
oniondelta commented 2 years ago

只有一個候選項,之前這邊是用 filter 過濾

context.input:push( key:repr()) 我這邊不知哪邊搞錯,無效且影響後面的 context:confirm_current_selection() 這幾天再繼續研究

shewer commented 2 years ago

怎麼不用Projection 呢
有點感覺 , commit preedit 就可以 不用candidate translator 加上 opencc 韓文-->漢語 如果有產生candidate

function init(env)
  local config= env.engine.schema.config
  lacal pat=config:get_list("hnc_hanja_mod/preedit_format")
  env.pp= Projection()
  env.pp:load(pat)
end
function func(inp,seg,env)
   local text = env.pp:apply(inp) --  ascii 輸出 韓文
   ...
end
shewer commented 2 years ago

只有一個候選項,之前這邊是用 filter 過濾

context.input:push( key:repr()) 我這邊不知哪邊搞錯,無效且影響後面的 context:confirm_current_selection() 這幾天再繼續研究

我對 https://github.com/hchunhui/librime-lua/blob/01c61b1d12ff5fb31711b150ad075422e1d7106d/src/types.cc#L52-L60 不了解 , 形碼很少 處理 segment

confirm_current_selection() 是上一次的 ,當 processor accepted 後 又再一次 compose() 如果 input 變更 大有機會 會影響 candidates 排序

oniondelta commented 2 years ago

試出來了!🥳 [a-z]+可以視覺上等同 menu (page_size = 0),零選項 BackSpace 可返回有選單項狀態 如果要直接刪字 shift + BackSpace fluency_editor 因素,數字標點等無法直接上屏,用 commit 解決

ps: 再修改增韓文 2set 會用到的 Shift+[QWERTOP]

engine:
  processors:
    - fluency_editor
local set_char = Set {"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z" } --> {a=true,b=true...}

local function proc.func(key,env)
  local engine = env.engine
  local context = engine.context
  local ascii_m = context:get_option("ascii_mode")

  local function check_qwertop()
    if key:eq(KeyEvent("Shift+Q")) then
      return true
    elseif key:eq(KeyEvent("Shift+W")) then
      return true
    elseif key:eq(KeyEvent("Shift+E")) then
      return true
    elseif key:eq(KeyEvent("Shift+R")) then
      return true
    elseif key:eq(KeyEvent("Shift+T")) then
      return true
    elseif key:eq(KeyEvent("Shift+O")) then
      return true
    elseif key:eq(KeyEvent("Shift+P")) then
      return true
    else
      return false
    end
  end

  local check_prefix = string.find(context.input, '=[a-z]*$')  --使反查鍵可展示全部選項

  if (not ascii_m) and set_char[key:repr()] and (not check_prefix) or (not ascii_m) and check_qwertop() and (not check_prefix) then
    local addend = string.gsub(key:repr(), 'Shift%+', '')
    context:reopen_previous_segment()
    context.input = context.input .. addend
    context:confirm_current_selection()
    return 1
  end
  return 2
end
shewer commented 2 years ago

試出來了!partying_face [a-z]+可以視覺上等同 menu (page_size = 0),零選項 BackSpace 可返回有選單項狀態 如果要直接刪字 shift + BackSpace fluency_editor 因素,數字標點等無法直接上屏,用 commit 解決

engine:
  processors:
    - fluency_editor

~~local function Set(tab) local rtab = {} for i,v in ipairs(tab) do rtab[v]=true end return rtab end~~ Set + Set Set * Set Set -Set

a=Set{'a','b','c'}
b=Set{'c','d','e'}
a - b --> {'a','b'}
a * b -->  {'c'}
a + b --> { 'a','b','c','d','e'}
-- librime-lua  內含 Set
local set_char = Set {"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z" , "Q", "W", "E", "R", "T" ,"O" ,"P"} --> {a=true,b=true...}

local function proc.func(key,env)
  local engine = env.engine
  local context = engine.context
  local ascii_m = context:get_option("ascii_mode")
  if set_char[key:repr()] and (not ascii_m) then  -- key:repr() match[a-z QWERTOP]
    local addend = key:repr():match("^[a-z]$") or ''
--     if (not addend_c) then  -- 不是很懂  這段 (QWERTOP]  append = "" ; return ?
--      addend=''
 --     return 2 ---  must be return 0-2
 --   end
    context:reopen_previous_segment()
    context.input = context.input .. addend
    context:confirm_current_selection()
    return 1
  end
  return 2
end
oniondelta commented 2 years ago

弄得差不多了,可以 page_size = 0 零選項了

由於韓文(諺文)2set 較單一,故沒有選字和排序問題, 但套用到拼音或是韓文對映漢字,也可以, 但展開選單後,左右切分再選字會有操作上瑕疵, 須不使用切分,從第一個字(或已有的詞)逐步選。 且選好後必須完全上屏, 否則後續鍵入會改變前面已選過字彙。

以下效果

test

shewer commented 2 years ago
local set_char = Set {"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z" , "Q", "W", "E", "R", "T" ,"O" ,"P"} 
local function proc.func(key,env)
   local engine = env.engine
   local context = engine.context
   -- pass  release  ctrl alt super   
    if  key:release() or key:ctrl() or key:alt() or key:super() then
        return 2
    end

  -- pass ascii_mode  check_prefix
    if context:get_option('ascii_mode') then return 2 end
    if context.find('=[a-z*$') then return 2 end --使反查鍵可展示全部選項

  -- accpted ascii as set_char
     local ascii = string.char(key.keycode)
     if set_char[ascii]  hen
      context:reopen_previous_segment()
      context.input = context.input .. ascii
      context:confirm_current_selection()
     return 1
   end
   return 2
 end

這是我截下的keyevent

Shift_L --> Shift+T --> Shift+Release+T --> Shift+Release+Shift_L t --> Release+t a --> Release+a g --> Release+g Shift_L --> Shift+H --> Shift+Release+H --> Shift+Release+Shift_L Shift_L --> Shift+H --> Shift+Release+H --> Shift+Release+Shift_L 一般 rime 是小寫輸入 ,大寫時 按Shift 字母 relelease.... 從此邏輯看 只要不是 alt super ctrl releace 可以不用理會 Shift+H
取出 keycode 就是目標 ascii 了 參照 librime soruce 有許多 事前預處理 release() ctrl) alt() ... 如果要收 ascii key 會排除 release() ctrl super alt 即可

processor function 只要區分 功能鍵 或是 可見 ascii 一般鍵 兩種鍵分開處理

shewer commented 2 years ago

只有一個候選項,之前這邊是用 filter 過濾

context.input:push( key:repr()) 我這邊不知哪邊搞錯,無效且影響後面的 context:confirm_current_selection() 這幾天再繼續研究

my bad
context:push_input( string)

oniondelta commented 2 years ago

好精簡的寫法呀!🤩👍🏻 真厲害! 理解並掛載實測了一番,good!

實測碼 ``` lua local set_char = Set {"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z" , "Q", "W", "E", "R", "T" ,"O" ,"P"} local function proc.func(key,env) local engine = env.engine local context = engine.context -- pass release ctrl alt super if key:release() or key:ctrl() or key:alt() or key:super() then return 2 end -- pass ascii_mode check_prefix if context:get_option('ascii_mode') then return 2 end -- if context.find('=[a-z]*$') then return 2 end --使反查鍵可展示全部選項 if string.find(context.input, '=[a-z]*$') then return 2 end --使反查鍵可展示全部選項 -- accpted ascii as set_char local ascii = string.char(key.keycode) if set_char[ascii] then context:reopen_previous_segment() context.input = context.input .. ascii context:confirm_current_selection() return 1 end return 2 end ```
oniondelta commented 2 years ago
E20221005 18:04:41.625133 440163776 lua_gears.cc:193] LuaProcessor::ProcessKeyEvent of kr_2set_0m_choice error(2): ../Library/Rime/lua/processor_kr_2set_0m_choice.lua:54: bad argument #1 to 'char' (value out of range)

功能都正常,但打字中會不斷報錯: 'char' (value out of range) 好似是 string.char(key.keycode) 出問題 怎樣的寫法可避免超出範圍? 這邊有限的功力,只想到 if 判斷 XD 還是換回舊寫法?

shewer commented 2 years ago

string.char range 0~255 1byte 可能是有些 KEY 沒㯗下吧 在 string.char( key.keycode ) 前 插入

if 又沒見不得人 ,只是覺得怪 ,還有什麼KEY 沒㯗下的

   if key.keycode >255 then
      log.error(  key:repr() , key.keycode , key.modifier )
      return 2
   end 
shewer commented 2 years ago
--  return char(0x20~0x7f)  or ""
local function ascii(key,pat)
   local pat = pat and ('^[%s]$'):format(pat) or "^.$"    
   local code = key.keycode
   return key.modifier <=1 and
        code >=0x20 and code <=0x7f and
        string.char(code):match(pat)  or  ""
end

ascii(key, 'a-zQWERTOP')

oniondelta commented 2 years ago

@ shewer 感謝!