Skip to main content

Configuration

Configure paw.el

After installing the above Dependencies, you can configure paw like config.el (which I may update frequently based on my need). You should better copy to your own configurations and tweak it based on your need.

Some csv dictionaries can be found in paw_dictionaries, you can download them and change the location. You can also convert from Anki Decks or Make your own, it is just text based dictionaries.

You can also check the language specific configurations below:

configure sdcv (stardict)

(setq paw-sdcv-program "/opt/homebrew/bin/sdcv" )
(setq paw-sdcv-dictionary-data-dir (expand-file-name "dict" doom-private-dir))
;; (setq paw-sdcv-env-lang (getenv "LANG")) ;; may need this on linux and android
(setq paw-sdcv-dictionary-list ;setup dictionary list for simple search
'("懒虫简明英汉词典"
"Collins Cobuild English Dictionary"
"小学馆-日中词典"
"日汉双解词典"
"EJ-EDict" "JE-EDICT_Kanji"
"日汉词典" "jmdict-ja-en" "KANJIDIC2" "新明解国語辞典"
"小学館中日辞典EB版" "広辞苑 第六版" "EJ-GENE95"
"jmdict-en-ja"
"JCEDict" "EDICT"
"JEDict" "ENAMDICT" "EJDic" "DrEye日汉词典" "DrEye4in1词典"))

Keybindings

paw supports Emacs native keybindings, evil, and transient menu (?).

Enable paw-annotation-mode automatically

You can add paw-annotation-mode to the corresponding hook, so that it can enable automatically after the corresponding mode is loaded:

(add-hook 'wallabag-entry-mode-hook #'paw-annotation-mode)
(add-hook 'nov-mode-hook #'paw-annotation-mode)
(add-hook 'elfeed-show-mode-hook #'paw-annotation-mode)
(add-hook 'eaf-mode-hook 'paw-annotation-mode)
(add-hook 'telega-webpage-mode-hook #'paw-annotation-mode)

Some modes like nov-mode, wallabag-entry-mode and eww-mode, adding above hook is not enough, you also need to add the following highlight functions :after the render function using advice-add:

(when (bound-and-true-p paw-annotation-mode)
(paw-clear-annotation-overlay)
(paw-show-all-annotations)
(if paw-annotation-show-wordlists-words-p
(paw-focus-find-words :wordlist t))
(if paw-annotation-show-unknown-words-p
(paw-focus-find-words)))

For more examples, please check: https://github.com/chenyanming/shrface/blob/master/config.el

One-Click or One-Key to query

By default, if paw-annotation-mode is enabled, you can One-Click to query the word. If you want to disable it:

(setq paw-view-note-click-enable nil) ;; Disable Left-Click One-Click to query feature

Or M-x paw-view-note-click-enable-toggle to toggle the One-Click feature on the fly.

You can also use paw-view-note-under-mouse to query the word under mouse, it is bound to by default. Move the mouse and hover on the word to be queried, and press. I called it as One-Key to query.

+You may also use paw-view-note-click-directly, which is bound to mouse-3 (Right Click). This is not controlled by paw-view-note-click-enable, it is also One-Click to query but using Right Click.+ -> I don't use it anymore.

Now,

Mouse-1 bound to paw-view-note-click (Click the word) Mouse-2 bound to paw-view-note (After Mouse-1 drag a text then Mouse-2 for query the selected area) Mouse-3 bound to paw-view-note-quit (Quit the view window)

Sound engines

Paw includes multiple sound engines that can be used to download audio files. The available sound engines include:

  • paw-say-word-cambridge
  • paw-say-word-oxford
  • paw-say-word-jpod101-alternate
  • paw-edge-tts-say-word
  • paw-youdao-say-word
  • paw-say-word-forvo
  • and more By default, the sequence in which these sound engines are used is defined by paw-say-word-functions.

The following configs control wheather say the word when you view by M-x paw-view-note

(defcustom paw-say-word-p t
"paw say word automatically"
:group 'paw
:type 'boolean)

(defcustom paw-say-word-supported-note-types '(word)
"The note types will be say automatically."
:group 'paw
:type '(repeat (choice symbol)))

In dashboard header, it is possible to toggle the paw-say-word-p (Voice) on the fly.

Audio player and volume control

Paw supports various audio players for pronunciation playback. The player program is automatically detected based on your system:

  • macOS: afplay (with native --volume support)
  • Other systems: mpv, mplayer, or mpg123

You can configure the audio player and volume:

;; Audio player program (auto-detected by default)
(setq paw-player-program "/usr/bin/afplay") ; or your preferred player

;; Volume control (0-100 range)
(setq paw-player-volume 50) ; 50% volume

Volume support by player:

  • mpv: Uses --volume=N parameter
  • mplayer: Uses -volume N parameter
  • afplay (macOS): Uses --volume N.N parameter (0.0-1.0 range)
  • mpg123: Uses -g N parameter for gain control
  • aplayer: No volume support, falls back to normal playback

Icons/Buttons

Paw support all major emacs icons packages, you can choose one of them.

  • svg-icon
  • nerd-icons (recommended if you use nerd fonts)
  • all-the-icons
  • pbm (image icons, recommended on android)
  • text (if all options are nil, fallback to pure text as icons)

The current checking sequence is svg -> pbm -> all-the-icons -> nerd-icons -> text. The first t option will be used first.

To enable pbm on android while use nerd-icon on non-android, we can configure like so:

;; svg icons
(setq paw-svg-enable nil)
;; Use pbm icons/buttons on android
(setq paw-pbm-enable (if (eq system-type 'android) t))
;; all the icons icon
(setq paw-all-the-icons-icon-enable nil)
;; all the icons button
(setq paw-all-the-icons-button-enable nil)
;; nerd icon/buttons
(setq paw-nerd-icons-icon-enable t)

Configure Language Detection

Set paw-detect-language-p to t, paw will use emacs-paw python cli (to use others tools check paw-detect-language-program) to detect the language for more accurate tts pronunciation and translation.

If you don't want to use language detection program, paw use simple ascii rate: paw-ascii-rate to detect the language, if the rate is greater than paw-ascii-rate, then it is considered as English, otherwise use paw-detect-language-program to detect the language of the TEXT, if paw-detect-language-p is t, or return as paw-non-ascii-language if paw-detect-language-p is nil.

Setup paw-python-program if necessary, if the pip module is installed with different python version, for android, set it to python3.10

Supported edge-tts voice:

  • paw-tts-english-voice
  • paw-tts-zh-cn-voice
  • paw-tts-zh-tw-voice
  • paw-tts-japanese-voice
  • paw-tts-korean-voice
  • Other languages: paw-tts-multilingual-voice Welcome PRs to add more languages :)

*paw-view-note* window configurations

If paw-view-note-window-auto-adjust is t (default), the window of *paw-view-note* will be automatically adjusted. If the height of the window is larger than the width, show it on the paw-view-note-vertical-position, otherwise show it on the paw-view-note-horizontal-position. Also, the windows width/height could be configured by paw-view-note-window-width and paw-view-note-window-height.

*paw-view-note* sections configurations

You can adjust the section order or remove the unwanted sections by configuring paw-view-note-sections

The order of the sections is the order of the list. Supported values are:

  • "Dictionaries": The online dictionaries buttons
  • "Search": The online search engine buttons
  • "Context": The context around the word/annotation
  • "Translation": The translation of the word/annotation
  • "Saved Meanings": The Saved Meanings of the word/annotation
  • "Meaning": The SDCV result of the word/annotation
  • "Notes": The notes of the word/annotation
  • "Anki": Special section for Anki

Back to original buffer

Normally, when you run paw-view-note, paw will switch to *paw-view-note* buffer. But there are some cases we want to stay at the original buffer, in this case:

  • Set paw-view-note-back-to-original-buffer as t (Default)
  • And add or remove the targeted major-mode into paw-view-note-back-to-original-buffer-supported-modes.

Configure Anki Integration

  1. PC: Install Anki.
  2. PC: Install AnkiConnect, add-on code: 2055492159.
  3. Android: Install AnkiDroid from F-Driod (We need it has full media access right, so that Emacs can copy audio files to it. Instead of using AnkiConect to download the audio, paw will download and cache the audio in paw-tts-cache-dir after the voice is pronounced.).
  4. Android: Install AnkiconnectAndroid
  5. Install Anki Editor if not installed.
  6. If you just want to try or use the default settings. Please download the default template Memrise Templates (Lτ) v3.32.apkg and import it into anki then you are all done.

If you want to use different template,

  1. Run paw-anki-configure-card-format to choose from default templates paw-anki-templates, or configure deck, note type, filed-name, and filed-values one by one temporarily. Currently Supported field-value:
    • word: the word to learn
    • exp: the explanation of the word
    • sound: the sound file of the word
    • note: the note of the word
    • cloze_note: the note of the word, word is clozed
    • cloze_note_exp_hint: the note of the word, word is clozed, use exp as hint
    • choices: the choices of the word
    • nil: empty field
    • Other values: the value of the field, it must be a string
  2. If you want to make it permanent, set paw-anki-deck, paw-anki-note-type, paw-anki-field-names and paw-anki-field-values manually in your config,
  3. Configure paw-online-word-servers, (setq paw-online-word-servers '(anki)) to enable anki server, or (setq paw-online-word-servers '(eudic anki)) to enable both eudic and anki servers.

PS: All types of annotations (not all are tested) could be added into Anki. Either using paw-add-online-word (anywhere), or paw-anki-editor-push-note(s) (dashboard) paw-anki-editor-delete-note(s) (dashboard).

paw-anki-editor-delete-note: Delete note at point to Anki.

paw-anki-editor-push-note: Push note at point to Anki.

paw-anki-editor-push-notes: Push notes of marked-entries in dashboard to anki, or push all anki notes in the same origin path (same file or same buffer). Same file name under paw-annotation-search-paths is also considerred same origin path.

paw-anki-editor-delete-notes: Delete anki notes of marked-entries in dashboard, or delete all anki notes in the same origin path (same file or same buffer), Same file name under paw-annotation-search-paths is also considerred same origin path.

Other templates:

The audio file is automatically downloaded and added to the anki note, if paw-anki-download-sound is t (default). The sound file download sequence are defined by paw-anki-download-sound-functions.

Configure Eudic Integration

  1. Apply Authorization key on https://my.eudic.net/OpenAPI/Authorization, and fill it into paw-authorization-keys before adding online words.
  2. Configure paw-online-word-servers, (setq paw-online-word-servers '(eudic)) to enable Eudic server, or (setq paw-online-word-servers '(eudic anki)) to enable both eudic and anki servers.

PS: Only online words can be added into Eudic. Mainly via command paw-add-online-word

Configure EAF Integration

Use my forks which add paw support.

Add the following bindings to your configuration:

(eaf-bind-key insert_or_paw_view_note_in_eaf "`" eaf-browser-keybinding)
(eaf-bind-key paw_view_note_in_eaf "`" eaf-pdf-viewer-keybinding)

Configure SilverDict Integration

SilverDict is a web-based dictionary server that works on multiple platforms including Android (via Termux). Unlike GoldenDict, SilverDict provides dictionary lookup through a web interface.

  1. Install and run SilverDict server on your device (see SilverDict documentation)

  2. Configure paw to use SilverDict: #+begin_src emacs-lisp ;; Set SilverDict as the external dictionary function (setq paw-external-dictionary-function 'paw-silverdict-search-details)

    ;; Configure host and port (defaults shown below) (setq paw-silverdict-host "localhost") ; or your server IP (setq paw-silverdict-port "2628") ; default SilverDict port

    ;; Configure the query path for your dictionary group (optional) ;; Default is "/api/query/Default%20Group/" ;; Change this to match your SilverDict dictionary group (setq paw-silverdict-query-path "/api/query/Default%20Group/") ;; Examples: ;; (setq paw-silverdict-query-path "/api/query/Chinese/") ;; (setq paw-silverdict-query-path "/api/query/YourGroup/") #+end_src

  3. For Android (Termux) setup, you may need to use 127.0.0.1 or localhost if running locally, or your device's IP address if running on another device on the same network.

Browser support

Browser Extension

  1. Firefox & Firefox Android https://addons.mozilla.org/en-US/firefox/addon/emacs-paw
  2. Chrome: https://chromewebstore.google.com/detail/paw/ofhodjclfalelhgjbfmdddekoghamlge
  3. Brave: Same as Chrome, but need to add @@||localhost^ into Create custom filters section of brave://settings/shields/filters if you need paw-server features.
  4. This browser extension enhances word interaction by underlining words on mouseover and capturing context when words are clicked. The captured information is sent to Emacs via org-protocol and displayed in the paw-view-note buffer.
  5. Update the server config inside the config page of the extension, and make sure the port number (paw-server-port) matches, for example, http://localhost:5001
  6. M-x paw-server. Run the paw-server, so that all words can be highlighted on browser.
  7. paw-server is optional, you don't need to run it, and still able to use the org-protocol feature. If you installed paw command line, you can run paw-server in several ways (see also paw_server for standalone usage):

Method 1: Emacs Integration (Original), same as M-x paw-server


paw run_server --database /home/damonchan/org/paw.sqlite --save-dir /tmp/ --port 5001 --wallabag-host https://example.com --wallabag-username username --wallabag-password password --wallabag-clientid clientid --wallabag-secret secret

Method 2: Standalone Mode (Enhanced, Recommended for Production, run on command line directly)


# Using environment variables (recommended)
export PAW_DATABASE_PATH="/home/damonchan/org/paw.sqlite"
export PAW_SAVE_DIR="/tmp/"
export PAW_PORT="5001"
export PAW_SERVER_TYPE="production" # or "flask"
export WALLABAG_HOST="https://example.com"
export WALLABAG_USERNAME="username"
export WALLABAG_PASSWORD="password"
export WALLABAG_CLIENTID="clientid"
export WALLABAG_SECRET="secret"

paw server

Method 3: Python Server (Moved)

The Python server functionality has been moved to a separate repository: paw_server. Please refer to that repository for server installation and usage instructions.

The standalone mode offers enhanced stability, better error handling, environment variable support, and waitress support for better performance.

Check more on: https://github.com/chenyanming/paw_org_protocol

org-protocol

If you don't want to use extension or sometimes can not use, add the following bookmarklet in browser, paste the following code as URL:


javascript:(function(){
var selection = window.getSelection().toString();
if (selection.length > 0) {
var url = encodeURIComponent(window.location.href);
var title = encodeURIComponent(document.title || "[untitled page]");
var body = encodeURIComponent(selection);
var parent = window.getSelection().getRangeAt(0).commonAncestorContainer.parentNode;
while (parent.nodeType !== Node.ELEMENT_NODE) {
parent = parent.parentNode;
}
var p_tag_parent = parent;
while (p_tag_parent.tagName !== undefined && p_tag_parent.tagName !== 'P') {
p_tag_parent = p_tag_parent.parentNode;
}
if (p_tag_parent !== document) {
parent = p_tag_parent;
}
var note = encodeURIComponent(parent.textContent || "");
location.href = 'org-protocol://paw?template=w&url=' + url + '&title=' + title + '&note=' + note + '&body=' + body;
}
}());

Select the word, and click the bookmark, the word will be shown in paw-view-note buffer.

Check more examples on js files in the root folder.

Coding

You can show anything on *paw-view-note* buffer!

For example, the following snippet shows the gptel result to *paw-view-note* buffer by using paw-view-note and paw-new-entry functions, use edge-tts to say the response out, use go-translate to transalte the response, also user can further interact (add to database etc) with the result in *paw-view-note* buffer.

(defun gptel-quick (&optional query)
"ASK AI with predefined prompts."
(interactive)
(require 'gptel)
(let* ((selected-text (when (use-region-p)
(buffer-substring-no-properties (region-beginning) (region-end))))
;; (current-buffer-text (buffer-substring-no-properties (point-min) (point-max)))
(additional-text (or selected-text ""))
(prompt (completing-read "Ask AI: "
'("Draft an outline"
"Draft anything"
"Draft an email"
"Draft a journal entry"
"Draft a meeting agenda"
"Explain in 12 words or less"
"Explain in 48 words or less"
"Explain in 100 words or less"
"Explain in 200 words or less"
"Write anything"
"Brainstorm ideas"
"Translate it to Chinese"))))
(when (string= prompt "") (user-error "A prompt is required."))
(deactivate-mark)
(setq gptel-last-prompt (format "%s. %s" prompt additional-text))
(gptel-request (or query gptel-last-prompt)
:system "You are an AI assistant that lives inside Emacs"
:callback
(lambda (response info)
(if (not response)
(message "gptel-quick failed with message: %s" (plist-get info :status))
(with-current-buffer (get-buffer-create "*gptel-quick*")
(let ((paw-say-word-p t) ;; say the response out
(lang (paw-check-language response)))
(paw-view-note (paw-new-entry response
:origin_type "gptel"
:serverp 3
:lang lang
:context (format "Question: %s\nAnswer: %s" gptel-last-prompt response))
:buffer-name paw-view-note-buffer-name
:display-func 'switch-to-buffer))))))))