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
, ormpg123
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
parametermplayer
: Uses-volume N
parameterafplay
(macOS): Uses--volume N.N
parameter (0.0-1.0 range)mpg123
: Uses-g N
parameter for gain controlaplayer
: 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
- PC: Install Anki.
- PC: Install AnkiConnect, add-on code: 2055492159.
- 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.). - Android: Install AnkiconnectAndroid
- Install Anki Editor if not installed.
- 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,
- Run
paw-anki-configure-card-format
to choose from default templatespaw-anki-templates
, or configure deck, note type, filed-name, and filed-values one by one temporarily. Currently Supported field-value:word
: the word to learnexp
: the explanation of the wordsound
: the sound file of the wordnote
: the note of the wordcloze_note
: the note of the word, word is clozedcloze_note_exp_hint
: the note of the word, word is clozed, use exp as hintchoices
: the choices of the wordnil
: empty field- Other values: the value of the field, it must be a string
- If you want to make it permanent, set
paw-anki-deck
,paw-anki-note-type
,paw-anki-field-names
andpaw-anki-field-values
manually in your config, - 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:
- MemCloze.apkg
- Anime Mining: https://github.com/donkuri/lapis
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
- Apply Authorization key on https://my.eudic.net/OpenAPI/Authorization, and fill it into
paw-authorization-keys
before adding online words. - 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.
- https://github.com/chenyanming/eaf-browser: Able to highlight all words in the database in the page, click to search word and show in paw-view-note buffer.
- https://github.com/chenyanming/eaf-pdf-viewer: Able to search the word under cursor by pressing one key (no need to select the word) and translate the sourrounded sentence, show in paw-view-note buffer.
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.
-
Install and run SilverDict server on your device (see SilverDict documentation)
-
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
-
For Android (Termux) setup, you may need to use
127.0.0.1
orlocalhost
if running locally, or your device's IP address if running on another device on the same network.
Browser support
Browser Extension
- Firefox & Firefox Android https://addons.mozilla.org/en-US/firefox/addon/emacs-paw
- Chrome: https://chromewebstore.google.com/detail/paw/ofhodjclfalelhgjbfmdddekoghamlge
- Brave: Same as Chrome, but need to add
@@||localhost^
intoCreate custom filters section
ofbrave://settings/shields/filters
if you need paw-server features. - 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.
- 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 - M-x
paw-server
. Run the paw-server, so that all words can be highlighted on browser. - 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 + '¬e=' + 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))))))))