mirror of
https://github.com/neovide/neovide.git
synced 2026-09-10 07:16:25 -04:00
feat: add Lua API of IME event handling (#3110)
* feat: add preedit support when enabled IME mode related to neovide#1931 * feat: support multi-line editing when IME is enabled * feat: add an API for handling IME events Default action is to insert commited text after the cursor. And, you can customize the behavior when preeditted or committed. * Revert to previous behavior If the text which you input is committed, process as key input regardless of mode of neovim * doc: update related contents of IME handling API * feat: support sending raw text and cursor offset * doc: add the content to enable preedit of IME * fix: broken link in faq * style: format ui_commands.rs * style: format api.md and faq.md * style: format api.md again 100 chars line len
This commit is contained in:
parent
24bae1bcce
commit
75ae946835
10
lua/init.lua
10
lua/init.lua
|
|
@ -147,4 +147,14 @@ M.enable_redraw = function()
|
|||
pcall(rpcnotify, "neovide.set_redraw", true)
|
||||
end
|
||||
|
||||
---@param preedit_raw_text string
|
||||
---@param cursor_offset? [integer, integer] (start_col, end_col) This values show the cursor begin position and end position. The position is byte-wise indexed.
|
||||
M.preedit_handler = function(preedit_raw_text, cursor_offset) end
|
||||
|
||||
---@param commit_raw_text string
|
||||
---@param commit_formatted_text string It's escaped.
|
||||
M.commit_handler = function(commit_raw_text, commit_formatted_text)
|
||||
vim.api.nvim_input(commit_formatted_text)
|
||||
end
|
||||
|
||||
_G["neovide"] = M
|
||||
|
|
|
|||
|
|
@ -23,6 +23,12 @@ use crate::{
|
|||
#[derive(Clone, Debug, AsRefStr)]
|
||||
pub enum SerialCommand {
|
||||
Keyboard(String),
|
||||
KeyboardAsIme {
|
||||
formatted: Option<String>,
|
||||
raw: String,
|
||||
commit: bool,
|
||||
cursor_offset: Option<(usize, usize)>,
|
||||
},
|
||||
MouseButton {
|
||||
button: String,
|
||||
action: String,
|
||||
|
|
@ -59,6 +65,44 @@ impl SerialCommand {
|
|||
.map(|_| ())
|
||||
.context("Input failed")
|
||||
}
|
||||
SerialCommand::KeyboardAsIme {
|
||||
formatted,
|
||||
commit,
|
||||
raw,
|
||||
cursor_offset,
|
||||
} => {
|
||||
if commit {
|
||||
// Notified ime commit event, the text is guaranteed not to be None.
|
||||
let text = formatted.unwrap();
|
||||
trace!("IME Input Sent: {}", &text);
|
||||
nvim.exec_lua(
|
||||
&format!("neovide.commit_handler([[{}]], [[{}]])", raw, text),
|
||||
vec![],
|
||||
)
|
||||
.await
|
||||
.map(|_| ())
|
||||
.context("IME Commit failed")
|
||||
} else {
|
||||
trace!("IME Input Preedit");
|
||||
if let Some((start_col, end_col)) = cursor_offset {
|
||||
nvim.exec_lua(
|
||||
&format!(
|
||||
"neovide.preedit_handler([[{}]], {{ {}, {} }})",
|
||||
raw, start_col, end_col
|
||||
),
|
||||
vec![],
|
||||
)
|
||||
.await
|
||||
.map(|_| ())
|
||||
.context("IME Preedit failed")
|
||||
} else {
|
||||
nvim.exec_lua(&format!("neovide.preedit_handler([[{}]])", raw), vec![])
|
||||
.await
|
||||
.map(|_| ())
|
||||
.context("IME Preedit failed")
|
||||
}
|
||||
}
|
||||
}
|
||||
SerialCommand::MouseButton {
|
||||
button,
|
||||
action,
|
||||
|
|
|
|||
|
|
@ -59,10 +59,21 @@ impl KeyboardManager {
|
|||
}
|
||||
WindowEvent::Ime(Ime::Commit(text)) => {
|
||||
log::trace!("Ime commit {text}");
|
||||
send_ui(SerialCommand::Keyboard(self.format_key_text(text, false)));
|
||||
send_ui(SerialCommand::KeyboardAsIme {
|
||||
formatted: Some(self.format_key_text(text, false)),
|
||||
raw: text.to_owned(),
|
||||
commit: true,
|
||||
cursor_offset: None,
|
||||
});
|
||||
}
|
||||
WindowEvent::Ime(Ime::Preedit(text, cursor_offset)) => {
|
||||
self.ime_preedit = (text.to_string(), *cursor_offset)
|
||||
self.ime_preedit = (text.to_string(), *cursor_offset);
|
||||
send_ui(SerialCommand::KeyboardAsIme {
|
||||
formatted: None,
|
||||
raw: text.to_owned(),
|
||||
commit: false,
|
||||
cursor_offset: *cursor_offset,
|
||||
});
|
||||
}
|
||||
WindowEvent::ModifiersChanged(modifiers) => {
|
||||
// Record the modifier states so that we can properly add them to the keybinding text
|
||||
|
|
|
|||
|
|
@ -4,8 +4,7 @@ The API fuctions are always available without any imports as long as Neovide is
|
|||
|
||||
## Redraw Control
|
||||
|
||||
`neovide.disable_redraw()`
|
||||
`neovide.enable_redraw()`
|
||||
`neovide.disable_redraw()` `neovide.enable_redraw()`
|
||||
|
||||
These can be used to by plugins to temporarily disable redrawing while performing some update. They
|
||||
can for exapmple, be used to prevent the cursor from temporarily moving to the wrong location, or to
|
||||
|
|
@ -39,3 +38,36 @@ if neovide and neovide.enable_redraw then neovide.enable_redraw() end
|
|||
|
||||
**Don't call these functions as a regular user, since you won't see any updates on the screen until
|
||||
the redrawing is enabled again, so it might be hard to type in the command.**
|
||||
|
||||
## IME handling
|
||||
|
||||
`neovide.preedit_handler(
|
||||
preedit_raw_text:string,
|
||||
cursor_offset:[start_col:integer, end_col:integer]
|
||||
)`
|
||||
`neovide.commit_handler(commit_raw_text:string, commit_formatted_text:string)`
|
||||
|
||||
These can be used to by your plugin to handle IME events. The pre-edit handler is
|
||||
called when yourinput method, such as Fcitx, IBus and MS-IME, sends pre-edit event.
|
||||
So, you have to handle pre-edit texts if you would like to support pre-edit event.
|
||||
The commit handler is called when your inputmethod sends commit event,
|
||||
which you decide some text on enabled IME.
|
||||
|
||||
In default, `preedit_handler()` is nothing to do and `commit_handler()` uses
|
||||
[`nvim_input()`](<https://neovim.io/doc/user/api.html#nvim_input()>)
|
||||
|
||||
```lua
|
||||
---@param preedit_raw_text string
|
||||
---@param cursor_offset? [integer, integer] (start_col, end_col)
|
||||
--- This values show the cursor begin position and end position.
|
||||
--- The position is byte-wise indexed.
|
||||
neovide.preedit_handler = function (preedit_raw_text, cursor_offset)
|
||||
-- handle pre-edit event...
|
||||
end
|
||||
|
||||
---@param commit_raw_text string
|
||||
---@param commit_formatted_text string It's escaped.
|
||||
neovide.commit_handler = function (commit_raw_text, commit_formatted_text)
|
||||
-- handle commit event...
|
||||
end
|
||||
```
|
||||
|
|
|
|||
|
|
@ -4,9 +4,9 @@ Commonly asked questions, or just explanations/elaborations on stuff.
|
|||
|
||||
## How can I use cmd-c/cmd-v to copy and paste?
|
||||
|
||||
Neovide doesn't add or remove any keybindings to neovim, it only forwards keys. Its likely that
|
||||
your terminal adds these keybindings, as neovim doesn't have them by default. We can replicate
|
||||
this behavior by adding keybindings in neovim.
|
||||
Neovide doesn't add or remove any keybindings to neovim, it only forwards keys. Its likely that your
|
||||
terminal adds these keybindings, as neovim doesn't have them by default. We can replicate this
|
||||
behavior by adding keybindings in neovim.
|
||||
|
||||
```lua
|
||||
if vim.g.neovide then
|
||||
|
|
@ -35,12 +35,10 @@ one for the popup menu.
|
|||
telescope.nvim is different here though. Instead of using the global `winblend` option, it has its
|
||||
own `telescope.defaults.winblend` configuration option, see [this comment in #1626].
|
||||
|
||||
[this comment in #1626]: https://github.com/neovide/neovide/issues/1626#issuecomment-1701080545
|
||||
|
||||
## How Can I Dynamically Change The Scale At Runtime?
|
||||
|
||||
Neovide offers the setting `g:neovide_scale_factor`, which is multiplied with
|
||||
the OS scale factor and the font size. So using this could look like
|
||||
Neovide offers the setting `g:neovide_scale_factor`, which is multiplied with the OS scale factor
|
||||
and the font size. So using this could look like
|
||||
|
||||
VimScript:
|
||||
|
||||
|
|
@ -113,50 +111,95 @@ vim.keymap.set({ "n", "v", "o" }, "<D-[>", function()
|
|||
end)
|
||||
```
|
||||
|
||||
## How To Enable Preedit Support Of IME?
|
||||
|
||||
By default, the IME preedit event—that is, the preview of the text being composed—is not
|
||||
implemented. You can implement this preview yourself by using preedit_handler().
|
||||
|
||||
Example:
|
||||
|
||||
```lua
|
||||
local ime_context = {
|
||||
base_col = 0,
|
||||
base_row = 0,
|
||||
preedit_col = 0,
|
||||
preedit_row = 0,
|
||||
}
|
||||
|
||||
---@param preedit_raw_text string
|
||||
---@param cursor_offset [integer, integer]: [start_col, end_col]
|
||||
preedit_handler = function(preedit_raw_text, cursor_offset)
|
||||
vim.api.nvim_buf_set_text(
|
||||
0,
|
||||
ime_context.base_row - 1,
|
||||
ime_context.base_col,
|
||||
ime_context.preedit_row - 1,
|
||||
ime_context.preedit_col,
|
||||
{}
|
||||
)
|
||||
ime_context.preedit_col = ime_context.base_col + string.len(preedit_raw_text)
|
||||
vim.api.nvim_buf_set_text(
|
||||
0,
|
||||
ime_context.base_row - 1,
|
||||
ime_context.base_col,
|
||||
ime_context.base_row - 1,
|
||||
ime_context.base_col,
|
||||
{ preedit_raw_text }
|
||||
)
|
||||
vim.api.nvim_win_set_cursor(0, { ime_context.preedit_row, ime_context.preedit_col })
|
||||
end
|
||||
```
|
||||
|
||||
Neovide also exposes a Lua function called commit_handler() in addition to preedit_handler(). For
|
||||
details, see [IME handling on the API page](api.html#ime-handling).
|
||||
|
||||
If you’d prefer not to set this up yourself, you can use
|
||||
[kanium3/neovide_ime.nvim](https://github.com/kanium3/neovide-ime.nvim). Please refer to that
|
||||
repository for more information. Example: Installation with Lazy.nvim
|
||||
|
||||
```lua
|
||||
return {
|
||||
"kanium3/neovide-ime.nvim"
|
||||
}
|
||||
```
|
||||
|
||||
Related: [PR #3110](https://github.com/neovide/neovide/pull/3110)
|
||||
|
||||
## Neovide Is Not Picking Up Some Shell-configured Information
|
||||
|
||||
...aka `nvm use` doesn't work, aka anything configured in `~/.bashrc`/`~/.zshrc`
|
||||
is ignored by Neovide.
|
||||
...aka `nvm use` doesn't work, aka anything configured in `~/.bashrc`/`~/.zshrc` is ignored by
|
||||
Neovide.
|
||||
|
||||
Neovide doesn't start the embedded neovim instance in an interactive shell, so your
|
||||
shell doesn't read part of its startup file (`~/.bashrc`/`~/.zshrc`/whatever the
|
||||
equivalent for your shell is). But depending on your shell there are other
|
||||
options for doing so, for example for zsh you can just put your relevant content
|
||||
into `~/.zprofile` or `~/.zlogin`.
|
||||
Neovide doesn't start the embedded neovim instance in an interactive shell, so your shell doesn't
|
||||
read part of its startup file (`~/.bashrc`/`~/.zshrc`/whatever the equivalent for your shell is).
|
||||
But depending on your shell there are other options for doing so, for example for zsh you can just
|
||||
put your relevant content into `~/.zprofile` or `~/.zlogin`.
|
||||
|
||||
## The Terminal Displays Fallback Colors/:terminal Does Not Show My Colors
|
||||
|
||||
Your colorscheme has to define `g:terminal_color_0` through
|
||||
`g:terminal_color_15` in order to have any effect on the terminal. Just setting
|
||||
any random highlights which have `Term` in name won't help.
|
||||
Your colorscheme has to define `g:terminal_color_0` through `g:terminal_color_15` in order to have
|
||||
any effect on the terminal. Just setting any random highlights which have `Term` in name won't help.
|
||||
|
||||
Some colorschemes think of this, some don't. Search in the documentation of
|
||||
yours, if it's your own, add it, and if you can't seem to find anything, open an
|
||||
issue in the colorscheme's repo.
|
||||
Some colorschemes think of this, some don't. Search in the documentation of yours, if it's your own,
|
||||
add it, and if you can't seem to find anything, open an issue in the colorscheme's repo.
|
||||
|
||||
## Compose key sequences do not work
|
||||
|
||||
One possible cause might be inconsistent capitalization of your locale
|
||||
settings, see [#1896]. Possibly you're also running an outdated version of
|
||||
Neovide.
|
||||
One possible cause might be inconsistent capitalization of your locale settings, see [#1896].
|
||||
Possibly you're also running an outdated version of Neovide.
|
||||
|
||||
[#1896]: https://github.com/neovide/neovide/issues/1896#issuecomment-1616421167.
|
||||
|
||||
Another possible cause is that you are using IME on X11. Dead keys with IME is
|
||||
not yet supported, but you can work around that either by disabling IME or
|
||||
configuring it to only be enabled in insert mode. See
|
||||
[Configuration](configuration.md).
|
||||
Another possible cause is that you are using IME on X11. Dead keys with IME is not yet supported,
|
||||
but you can work around that either by disabling IME or configuring it to only be enabled in insert
|
||||
mode. See [Configuration](configuration.md).
|
||||
|
||||
## Font size is weird with high dpi display on x11
|
||||
|
||||
Winit looks in multiple locations for the configured dpi.
|
||||
Make sure its set in at least one of them. More details
|
||||
here: [#2010](https://github.com/neovide/neovide/issues/2010#issuecomment-1704416685).
|
||||
Winit looks in multiple locations for the configured dpi. Make sure its set in at least one of them.
|
||||
More details here: [#2010](https://github.com/neovide/neovide/issues/2010#issuecomment-1704416685).
|
||||
|
||||
## How to turn off all animations?
|
||||
|
||||
Animations can be turned off by setting the following global
|
||||
variables:
|
||||
Animations can be turned off by setting the following global variables:
|
||||
|
||||
```lua
|
||||
vim.g.neovide_position_animation_length = 0
|
||||
|
|
@ -170,43 +213,43 @@ vim.g.neovide_scroll_animation_length = 0.00
|
|||
|
||||
## macOS Login Shells
|
||||
|
||||
Traditionally, Unix shells use two main configuration files that are executed
|
||||
before a user can interact with the shell: a profile file and an rc file.
|
||||
Traditionally, Unix shells use two main configuration files that are executed before a user can
|
||||
interact with the shell: a profile file and an rc file.
|
||||
|
||||
- **Profile File:** This file is typically executed once at login to set up
|
||||
the user's environment.
|
||||
- **RC File:** This file is executed every time a new shell is created to
|
||||
configure the shell itself.
|
||||
- **Profile File:** This file is typically executed once at login to set up the user's environment.
|
||||
- **RC File:** This file is executed every time a new shell is created to configure the shell
|
||||
itself.
|
||||
|
||||
In the case of Zsh, which has been the default shell on macOS since version
|
||||
10.15, the configuration files used are `.zprofile` and `.zshrc`.
|
||||
In the case of Zsh, which has been the default shell on macOS since version 10.15, the configuration
|
||||
files used are `.zprofile` and `.zshrc`.
|
||||
|
||||
### Bash Differences
|
||||
|
||||
Unlike Zsh, Bash behaves differently. It only reads `.bashrc` if the shell
|
||||
session is both interactive and non-login. This distinction might have been
|
||||
overlooked when macOS transitioned from tcsh to bash in OSX 10.2 Jaguar,
|
||||
leading developers to place their setup entirely in `.profile` since `.bashrc`
|
||||
would rarely be executed, especially when starting a new terminal.
|
||||
Unlike Zsh, Bash behaves differently. It only reads `.bashrc` if the shell session is both
|
||||
interactive and non-login. This distinction might have been overlooked when macOS transitioned from
|
||||
tcsh to bash in OSX 10.2 Jaguar, leading developers to place their setup entirely in `.profile`
|
||||
since `.bashrc` would rarely be executed, especially when starting a new terminal.
|
||||
|
||||
With the shift to Zsh as the default shell, both `.zprofile` and `.zshrc` are
|
||||
executed when starting an interactive non-login shell.
|
||||
With the shift to Zsh as the default shell, both `.zprofile` and `.zshrc` are executed when starting
|
||||
an interactive non-login shell.
|
||||
|
||||

|
||||
|
||||
_Regarding to the moment when Neovide launches, it does not start an
|
||||
interactive shell session, meaning the .bashrc file is not executed. Instead,
|
||||
the system reads the .bash_profile file. This behavior stems from the
|
||||
difference in how interactive and login shells process configuration files._
|
||||
_Regarding to the moment when Neovide launches, it does not start an interactive shell session,
|
||||
meaning the .bashrc file is not executed. Instead, the system reads the .bash_profile file. This
|
||||
behavior stems from the difference in how interactive and login shells process configuration files._
|
||||
|
||||
### macOS Specifics
|
||||
|
||||
On macOS, the graphical user interface used for system login does not execute
|
||||
`.zprofile`, as it employs a different method for loading system-level global
|
||||
settings. This means that terminal emulators must run shells as login shells
|
||||
to ensure that new shells are properly configured, avoiding potential issues
|
||||
from missing setup processes in `.zprofile`. This necessity arises because
|
||||
there is no `.xsession` or equivalent file on macOS to provide initial
|
||||
settings or global environment variables to terminal sessions[^1].
|
||||
On macOS, the graphical user interface used for system login does not execute `.zprofile`, as it
|
||||
employs a different method for loading system-level global settings. This means that terminal
|
||||
emulators must run shells as login shells to ensure that new shells are properly configured,
|
||||
avoiding potential issues from missing setup processes in `.zprofile`. This necessity arises because
|
||||
there is no `.xsession` or equivalent file on macOS to provide initial settings or global
|
||||
environment variables to terminal sessions[^1].
|
||||
|
||||
[^1]: [Why are interactive shells on OSX login shells by default?](https://unix.stackexchange.com/questions/119627/why-are-interactive-shells-on-osx-login-shells-by-default)
|
||||
\[^1\]:
|
||||
[Why are interactive shells on OSX login shells by default?](https://unix.stackexchange.com/questions/119627/why-are-interactive-shells-on-osx-login-shells-by-default)
|
||||
|
||||
[#1896]: https://github.com/neovide/neovide/issues/1896#issuecomment-1616421167.
|
||||
[this comment in #1626]: https://github.com/neovide/neovide/issues/1626#issuecomment-1701080545
|
||||
|
|
|
|||
Loading…
Reference in a new issue