Skip to content

Repository files navigation

NSKK: Japanese input for Emacs

https://github.com/takeokunn/nskk.el/actions/workflows/ci.yml/badge.svg https://img.shields.io/badge/License-GPL%20v3-blue.svg

Overview

NSKK is a Japanese input method for Emacs based on SKK (Simple Kana to Kanji). Type a reading in romaji, start conversion with SPC, and select a candidate from an SKK dictionary.

Features

Requirements

Requires Emacs 29.1 or later. No external ELPA packages are required.

SKK Input

  • Hiragana, katakana, half-width katakana, and Latin input
  • SKK-JISYO dictionaries, user dictionary registration, and skkserv lookup
  • Standard romaji and AZIK input
  • Conversion markers: ▽ for a reading, ▼ for candidate selection

Installation

From source

Clone this repository and add its src directory to load-path. Replace the example path with your checkout’s location:

(add-to-list 'load-path "/path/to/nskk.el/src")

Quick Start

Minimal Configuration

(require 'nskk)
(nskk-global-mode 1)

;; After nskk-global-mode is enabled:
;; C-j       → switch to hiragana input (from ascii mode)
;; C-x C-j   → toggle nskk-mode on/off in current buffer

By default, NSKK searches system locations for SKK-JISYO files and falls back to Emacs’s built-in ja-dic if none are found.

With System Dictionary

To choose dictionaries explicitly, use this configuration instead of the minimal configuration. Replace the paths with existing dictionary files before enabling NSKK.

(require 'nskk)
(setopt nskk-dict-system-dictionary-files
        '("/usr/share/skk/SKK-JISYO.L"
          "/usr/share/skk/SKK-JISYO.jinmei"
          "/usr/share/skk/SKK-JISYO.geo"))
(nskk-global-mode 1)

Configuration Example

(use-package nskk
  :custom
  ;; Start in hiragana mode (optional, default is ascii)
  (nskk-state-default-mode 'hiragana)

  (nskk-dict-system-dictionary-files
   '("/usr/share/skk/SKK-JISYO.L"))

  (nskk-dict-user-dictionary-file "~/.nskk/jisyo")

  ;; Show candidate list after 2nd SPC (default: 5)
  (nskk-henkan-show-candidates-nth 2)
  (nskk-henkan-number-to-display-candidates 7)

  :config
  (nskk-global-mode 1))

Usage

Mode Switching

FromKeyToIndicator
AnyC-x C-jToggle on/off
asciiC-jhiraganaかな
hiraganaqkatakanaカナ
hiraganallatinSKK
hiraganaLfull-width全英
hiragana/abbrevaA

Conversion Flow

In hiragana mode, type Kanji to enter the reading ▽かんじ. The uppercase K starts the conversion reading. Press SPC to look up candidates and display the first one. While a single candidate is displayed inline, use SPC (next) or x (previous), then press C-j to commit without a newline, or RET to commit and insert a newline. C-g returns from candidate selection to the reading; another C-g cancels the reading.

Once the candidate list opens, select a visible candidate with its labeled key. SPC advances a page; x, C-p, or DEL returns to the previous page. From the first page, they return to the previous inline candidate, or to the reading when nskk-henkan-show-candidates-nth is 1. RET and C-j leave the list open, and unrecognized keys are consumed without changing the reading or input mode. A configured selection key for a visible candidate takes precedence over these controls.

If no candidate is found, or you advance past the available candidates, NSKK prompts for a word to register in the user dictionary. Enter the word in the minibuffer and press RET, or press C-g to cancel. To use NSKK kana input inside this prompt, set nskk-use-kana-in-registration to t; it is disabled by default.

Key Bindings

Mode Control

KeyCommandDescription
C-x C-jnskk-toggle-modeToggle NSKK in current buffer
C-jnskk-kakuteiCommit reading or inline candidate; switch direct input to hiragana
qnskk-handle-qToggle hiragana ↔ katakana
lnskk-handle-lSwitch to Latin input
Lnskk-handle-upper-lSwitch to full-width latin (JIS X 0208)
/nskk-handle-slashEnter abbrev mode

Conversion (Henkan)

KeyCommandDescription
SPCnskk-handle-spaceStart conversion / next candidate
xnskk-handle-xPrevious candidate
Xnskk-handle-upper-xPurge candidate from user dictionary
RETnskk-handle-returnCommit inline candidate or reading and insert a newline
C-gnskk-handle-cancelCancel conversion or preedit
a s d f j k ldirect selectSelect candidate in list mode (default keys)
C-nnskk-handle-ctrl-nNext inline candidate; ignored in candidate list unless configured as a visible selection key; otherwise commit any reading and move down
C-pnskk-handle-ctrl-pPrevious candidate during selection; otherwise commit any reading and move up
C-/nskk-undoUndo input or candidate selection; ordinary Emacs Undo after commit

Ordinary Undo does not resume conversion: a restored is ordinary buffer text, not an active conversion marker. Continue Undo to remove that text. To reopen the last committed conversion at the next candidate, use M-x nskk-undo-kakutei. Moving the cursor or typing after the committed word does not prevent this command from reopening it. This command has no default key binding and cannot be repeated consecutively or during conversion.

Cursor Movement (with an Inline Candidate)

KeyBehavior
↑ / C-pSelect previous candidate
↓ / C-nSelect next candidate
← / C-bCommit candidate + move backward
→ / C-fCommit candidate + move forward

Line Navigation

These bindings leave an open candidate list unchanged unless configured to select a visible candidate.

KeyBehavior
C-a / <home>Commit any candidate or reading, then go to beginning of line
C-e / <end>Commit any candidate or reading, then go to end of line

Other Keys

KeyCommandDescription
;nskk-handle-semicolon-keySticky shift: start a reading when idle, or mark the okurigana boundary in preedit. Small っ in AZIK
#nskk-handle-hashStart numeric input; dictionary keys beginning with # expand numeric candidates
DELnskk-handle-backspaceDelete last preedit char / cancel inline conversion / go back in candidate list
TABnskk-handle-tabDynamic completion (preedit) / indent-for-tab-command

Input Modes

ModeIndicatorDescription
asciiSKKDirect ASCII input (pass-through)
latinSKKDirect input selected with l
hiraganaかなHiragana input
katakanaカナKatakana input
katakana-半角カナHalf-width katakana input
jisx0208-latin全英Full-width latin (JIS X 0208)
abbrevaALiteral dictionary key input: /word SPC looks up word

Half-width katakana has no default switching key. In an NSKK buffer, evaluate (nskk-set-mode 'katakana-半角) or bind a command that calls it.

Configuration

SKK Server (skkserv)

(setopt nskk-server-enable t)
(setopt nskk-server-host "localhost")
(setopt nskk-server-portnum 1178)

AZIK Extended Romaji

(setopt nskk-converter-romaji-style 'azik)

;; Keyboard layout (us101 or jp106, default: jp106)
(setopt nskk-azik-keyboard-type 'jp106)

AZIK adds shortened input sequences:

  • kz → かん
  • sz → さん
  • kh → くう

Optional Features

These modules are included in this repository and loaded when NSKK starts. The display and integration settings below are disabled by default. Region commands can be called without enabling an option.

FeatureModuleEnable with
Annotation displaynskk-annotation(setopt nskk-show-annotation t)
Inline mode displaynskk-show-mode(setopt nskk-show-mode-show t)
Inline candidate displaynskk-inline(setopt nskk-show-inline t)
Context auto-modenskk-context(nskk-context-global-mode 1)
Isearch integrationnskk-isearch(setopt nskk-isearch-enable t)
Region operationsnskk-regionFor example, M-x nskk-hiragana-region or M-x nskk-katakana-region
Program dictionariesnskk-program-dictionary(setopt nskk-program-dict-enable t)

Context auto-mode switches to Latin input outside strings and comments in programming modes. It does not automatically switch back to kana input.

nskk-study ships with NSKK but is not loaded automatically. Require it before the first nskk-mode activation so that activation loads its saved learning data. Contextual learning reorders candidates based on the previously confirmed word:

(require 'nskk-study)

Dynamic Completion

;; How completion is presented in preedit.
;;   capf  -- completion-at-point-functions (default)
;;   cycle -- DDSKK-style TAB cycling, replacing preedit text directly
(setopt nskk-dcomp-style 'capf)

;; In cycle style, show a list below preedit while cycling
(setopt nskk-dcomp-multiple-activate t)

Program Dictionaries

A program dictionary answers lookups by running an external command or an Emacs Lisp function instead of reading an SKK-JISYO file.

(setopt nskk-program-dict-enable t)

;; Each entry is a command template or a function. In a template the
;; whitespace-delimited token %s becomes one argv element; without it the
;; reading is sent on stdin. No shell interpolation is performed.
(setopt nskk-program-dicts '("/usr/local/bin/my-dict %s"))

;; Wait budget in seconds per external command (default 1.0)
(setopt nskk-program-dict-timeout 1.0)

A function entry is called with the reading and must return nil or a list of candidate strings. Commands run through make-process; stdout is capped at 1 MiB and parsed as SKK, skkserv, or one-candidate-per-line output, and a command that times out, exceeds the cap, or exits nonzero counts as a miss.

nskk-program-dict-enable and nskk-program-dicts are marked :risky, so Emacs will not accept them from a file-local variable without confirmation. Entries name a command or function NSKK will execute; only add sources you trust. With nskk-program-dict-enable nil, the default, lookups fail immediately and nskk-program-dicts is never consulted.

Emacs Lisp Extensions

Require nskk before evaluating these examples. Input rules, key bindings, and presentation can be changed with ordinary Emacs Lisp; extensions do not need to call the internal Prolog or continuation APIs.

Keys and input state

Edit nskk-mode-map directly, including after nskk-mode is enabled. nskk-current-key-state returns normal, preedit, or converting. This command switches to hiragana only outside preedit and conversion:

(require 'nskk)

(defun my-nskk-hiragana ()
  (interactive)
  (when (eq (nskk-current-key-state) 'normal)
    (nskk-set-mode 'hiragana)))

(define-key nskk-mode-map (kbd "C-c j") #'my-nskk-hiragana)

Persistent input rules

nskk-converter-user-rules adds or replaces exact romaji rules. These rules take precedence over the selected style, including nskk-azik-conversion-table, and survive style changes and reloads.

(require 'nskk)

(setopt nskk-converter-user-rules '(("qa" . "くぁ")
                                   ("ka" . "")))

setopt rebuilds the conversion table immediately. After using setq, call (nskk-converter-reload-style nskk-converter-romaji-style) to apply the value. A failed rebuild keeps the previous working table. Remove an entry and reload to restore the style’s rule; this option does not delete built-in rules. nskk-converter-add-rule and nskk-converter-remove-rule remain temporary edits to the current table.

Candidate list UI

The show hook receives the full candidate list and its zero-based page start. The hide hook takes no arguments. The selector receives a key character, the full list, and the page start; it returns an absolute candidate index or nil. This example replaces the list overlay with echo-area output and reuses the standard selector:

(require 'nskk)

(defun my-nskk-show-candidates (candidates start)
  (message "%s"
           (mapconcat #'identity
                      (cl-mapcar (lambda (key candidate)
                                   (format "%c:%s" key candidate))
                                 nskk-henkan-show-candidates-keys
                                 (seq-take (nthcdr start candidates)
                                           nskk-henkan-number-to-display-candidates))
                      "  ")))

(defun my-nskk-hide-candidates ()
  (message nil))

(setq nskk-henkan-show-candidates-functions '(my-nskk-show-candidates)
      nskk-henkan-hide-candidates-functions '(my-nskk-hide-candidates)
      nskk-henkan-select-candidate-by-key-function
      #'nskk-candidate-list-select-by-key)

These variables have standard UI defaults; setting them to nil disables their respective callbacks. Use setq-local for a buffer-specific UI. Changes take effect at the next candidate operation: NSKK hides the old UI before showing and selecting through the new one. Cleanup uses the hide callbacks captured for the UI that was shown, even if settings change again. Hide callbacks must release resources after a partially failed show as well as after a completed show. NSKK attempts all hide callbacks on cleanup and preserves the original error or quit condition.

The following example is an alternative to the replacement UI above. For text-only changes, keep the standard UI and set nskk-candidate-format-function instead. It receives page candidates, selection key characters, and the remaining candidate count, and must return the overlay’s after-string. nskk-henkan-show-candidates-keys controls both the displayed labels and standard key selection without re-enabling NSKK.

(require 'nskk)

(defun my-nskk-candidate-text (candidates keys remaining)
  (concat (nskk-candidate-format candidates keys remaining) "  [選択]"))

(setopt nskk-candidate-format-function #'my-nskk-candidate-text)

Mode labels and cursor faces

nskk-mode-display-alist entries have the form (MODE LABEL FACE HELP CURSOR-FACE). Mode-line text, transient mode labels, and cursor colors read this same table. nskk-mode-display-properties returns the four properties for a mode, or nil when it has no entry. This changes the hiragana label without replacing the other modes:

(require 'nskk)

(setf (alist-get 'hiragana nskk-mode-display-alist)
      '("" nskk-modeline-hiragana-face "ひらがな" nskk-cursor-hiragana))
(nskk-modeline-update)

Changes are read on the next display update even if the input mode has not changed. Call nskk-modeline-update to refresh the current buffer immediately. For buffer-local changes, first copy the table with (setq-local nskk-mode-display-alist (copy-tree nskk-mode-display-alist)).

Inline candidate text

nskk-inline-format-function receives a candidate string and the current nskk-show-inline style, and must return an after-string. NSKK still owns the overlay and its cleanup. Styles t and horizontal place text beside preedit; vertical places it below. Set nskk-show-inline to nil to disable it.

(require 'nskk)

(defun my-nskk-inline-text (candidate style)
  (concat (if (eq style 'vertical) "\n" " ") "[" candidate "]"))

(setopt nskk-inline-format-function #'my-nskk-inline-text
        nskk-show-inline t)

Customization Group

M-x customize-group RET nskk RET

Development

Commands

CommandDescription
make compileByte-compile all modules
make testRun all tests
make test-unitRun unit tests only
make test-integrationRun integration tests only
make test-e2eRun end-to-end tests only
make lintRun checkdoc
make package-lintRun package-lint
make benchRun the benchmark suite
make cleanRemove *.elc files

CI gates on make compile, make test, make lint and make package-lint across Emacs 29.1, 29.4, 30.1 and snapshot.

Changelog

See CHANGELOG.md.

Contributing

See CONTRIBUTING.md for development and pull request guidelines.

License

GPL-3.0-or-later

Acknowledgments

  • DDSKK
  • All SKK dictionary contributors

About

A next-generation SKK (Simple Kana to Kanji) Japanese input method for Emacs 29.1+

Topics

Resources

Contributing

Stars

28 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages