# Emacs - center/top point when - moving to text/tag search hit - going to man page section - opening eww on an anchor - visiting a function from its Help buffer - make font-lock stop background at fill-column or max(len(line) for line in paragraph) rather than window-width when text spans >1 lines - shell-mode - add faces instead of reusing font-lock-{comment,string} - understand `autocd` and `cd !$` - use Bash completions (e.g. `ls TAB` in a folder with one file) - [.dir-locals changed priorities][bug#30008] between subfolder and major mode from 25 to 26 - eshell: `ls --group-directories-first` does not color folders - emoji support - eww, gnus-article: adapt filling to window width changes - scroll-lock-mode - cursor stuck on lines wrapped by visual-line-mode - cursor stuck on lines with 😛 - scroll when going down newline with forward-… - prevent kills in password prompts from ending up in the clipboard (.authinfo.gpg, sudo…) - matching-paren analysis fails: `;; (here is\n;; a comment)` - some modes redefine C-M-h, which makes this binding hard to override; could mark-defun consult functions/values exposed by major modes instead? - make ellipses for "invisible" text easily customizable (src/xdisp.c) - Man-mode: make isearch skip end-of-line hyphens - whitespace-mode: skip line/wrap-prefix variables and properties - when opening `.gpg` files in a TTY, some characters (e.g. TAB) are swallowed by Emacs instead of being forwarded to the gpg prompt; these characters are then inserted in the decrypted file's buffer (see `epa-file-insert-file-contents`) - let TRAMP fetch Google Drive credentials from .authinfo.gpg - icomplete's C-j does not choose the first completion as advertised on empty input; it chooses ".", which AFAICT comes from the fact that icomplete-exhibit calls completion-pcm--filename-try-filter while icomplete-force-complete-and-exit simply calls minibuffer-force-complete-and-exit - likewise, if a folder contains foo.c and foo.o, "C-x C-f foo" hides foo.o, yet C-j completes to foo.o - minor-mode to automatically surround word with delimiter when typed in the middle of a word - customize " Compiling" mode-line indicator [bug#30008]: https://debbugs.gnu.org/cgi/bugreport.cgi?bug=30008 ## Make " Narrow" lighter customizable The " Narrow" string comes from `src/xdisp.c:decode_mode_spec`: ``` c case 'n': if (BUF_BEGV (b) > BUF_BEG (b) || BUF_ZV (b) < BUF_Z (b)) return " Narrow"; ``` This is probably just a matter of returning the contents of a Lisp variable instead of this constant string. TODO: 1. get the string value of a variable in C 2. define a customizable string variable 3. write a news entry 4. write a patch 5. extra credits: display string properties ### Get the string value of a variable in C `decode_mode_spec` has some relevant snippets: - Given a `Lisp_Object obj`, `SSDATA(obj)` gives the string value as a `char*`. - How to get a variable's `Lisp_Object`? - `BVAR` works for buffer-local variables - `V${lispname//-/_}` ### Define a customizable string variable #### Defining variables visible to C code The C macro `DEFVAR_LISP(string-name, field-name)` does the following: define a static `Lisp_Objfwd` variable v get the address of globals._f##field-name &f defvar_lisp(v, string-name, &f) As explained in the comments above `DEFVAR_LISP`, `globals` is a global variable defined in `globals.h`, which is "auto-generated by make-docfile" and exposes fields, `#define`s and `Lisp_Object`s for every global variable. make-docfile (`lib-src/make-docfile.c`) takes C files as input and searches all occurences of `^ +DEFSYM[ \t(]`, `^ +DEFVAR_[ILB]` or `^DEFU`, analyses what comes after and generates appropriate definitions for `globals.h`. `defvar_lisp` allocates a symbol using `Fmake_symbol`. #### Making it customizable `lisp/cus-start.el` defines customizable properties of symbols defined by C code. AFAICT, there is no need to assign the default value right after defining the variable with `DEFVAR_LISP`: e.g. `shell-file-name` is `DEFVAR_LISP`ed in `src/callproc.c` and its default value is set in… Mmm. Not in `cus-start.el`. There is this snippet in `callproc.c:init_callproc`: ``` c sh = getenv ("SHELL"); Vshell_file_name = build_string (sh ? sh : "/bin/sh"); ``` But when starting with `SHELL=rofl emacs -Q`, Custom says that the value "has been changed outside Customize". Changed from what to what? `cus-start.el` may contain a hint: ``` elisp ;; Elements of this list have the form: ;; … ;; REST is a set of :KEYWORD VALUE pairs. Accepted :KEYWORDs are: ;; :standard - standard value for SYMBOL (else use current value) ;; … ``` Except that nope, this does not work. Giving `:standard " Narrow"` and looking at the variable in Custom yields narrow-lighter: nil [State]: CHANGED outside Customize. (mismatch) A better example might be `overlay-arrow-string`, whose default value is set right after `DEFVAR_LISP` by calling `build_pure_c_string`. Why `build_pure_c_string` and not `build_string`? From "(elisp) Pure Storage": > Emacs Lisp uses two kinds of storage for user-created Lisp objects: > “normal storage” and “pure storage”. Normal storage is where all > the new data created during an Emacs session are kept (see Garbage > Collection). Pure storage is used for certain data in the preloaded > standard Lisp files—data that should never change during actual use > of Emacs. > > Pure storage is allocated only while ‘temacs’ is loading the > standard preloaded Lisp libraries. In the file ‘emacs’, it is > marked as read-only (on operating systems that permit this), so that > the memory space can be shared by all the Emacs jobs running on the > machine at once. "(elisp) Building Emacs" explains that "temacs" is the minimal Elisp interpreter built by compiling all C files in `src/`; temacs then loads Elisp sources and creates the "emacs" executable by dumping its current state into a file. ### Debug stuff #### Unicode characters represented as octal sequences Trying to customize the new variable to any string with non-ASCII characters fails: they show up as sequences of backslash-octal codes. For some reason they show up fine in the Help and Custom buffers. Things to investigate: 1. Should the `Lisp_Object` be created with something other than `build_pure_c_string`? 🙅 2. What does the code calling `decode_mode_spec` do with the returned string? **🎉** 3. (Does `SSDATA` make some transformation before returning the string? 🤷) 4. (Should a specialized Custom setter be defined? 🤷) ##### Should the `Lisp_Object` be created with something other than `build_pure_c_string`? Maybe this would work? ``` c Vnarrow_lighter = make_multibyte_string(" Narrow", strlen(" Narrow"), strlen(" Narrow)"); ``` That looks too ugly though, let's try something else. Maybe `STRING_SET_MULTIBYTE(Vnarrow_lighter)` would help? *compiles and tries* … Nope, it does not. ##### What does the code calling `decode_mode_spec` do with the returned string? ``` c spec = decode_mode_spec (it->w, c, field, &string); multibyte = STRINGP (string) && STRING_MULTIBYTE (string); ``` *slowly turns around* *finds `string` standing right there with a blank stare* Gah! How long have you been there? ``` c /* Return a string for the output of a mode line %-spec for window W, generated by character C. […] Return a Lisp string in *STRING if the resulting string is taken from that Lisp string. […] */ static const char * decode_mode_spec (struct window *w, register int c, int field_width, Lisp_Object *string) { Lisp_Object obj; /* … */ obj = Qnil; *string = Qnil; switch (c) { /* … */ } if (STRINGP (obj)) { *string = obj; return SSDATA (obj); } else return ""; } ``` Alright then: ``` c case 'n': if (BUF_BEGV (b) > BUF_BEG (b) || BUF_ZV (b) < BUF_Z (b)) obj = Vnarrow_lighter; break; ``` ## Better out-of-the-box display for FORM FEED By default, FORM FEED is displayed as a dumb `^L` glyph. This is surprising considering it shows up in so many places: Emacs source files, help buffers (e.g. `describe-mode`)… You can even see it in source files of other GNU projects, like GCC. "Pages" are important enough to have their own navigation and narrowing commands, yet their default delimiter is displayed as an unassuming control character. I like [`page-break-lines`]'s approach; having this kind of display by default would make it more obvious that this character serves an actual purpose. As it stands, it looks no different from some stray CARRIAGE RETURN. This could be re-used by e.g.: - `describe-symbol`, which uses the following ~~method~~ hack to visually break up multiple symbol definitions: ``` lisp (insert "\n\n" (eval-when-compile (propertize "\n" 'face '(:height 0.1 :inverse-video t))) "\n") ``` - Custom buffers, where sections are delimited visually with a 999-character wide underlined space. Full disclosure : This reflection started because moving over this underlined space with `truncate-lines` on causes the screen to jump horizontally. This specific problem should be fixable without dragging FORM FEED display into the discussion, but I feel like the latter is the more interesting issue ([who on Earth] enables `truncate-lines` by default anyway). [`page-break-lines`]: https://github.com/purcell/page-break-lines [who on Earth]: https://gitlab.com/peniblec/dotfiles/blob/master/.emacs-custom.el ## ERC - move timestamp to a better position (see `stamp` module) - play well with whitespace-mode ## Language support - fix builtin/keyword distinction for Bash & Python3 ## Third-party ### magit - customize current-tag function so that one can add `--first-parent` - prevent section highlight overlay from hiding tag face background - fix copy-pasted docstring for magit-diff-context-highlight ### markdown-mode - support [shortcut reference links] - move point past header after C-c C-t !/@ - update sub-superscript regex to allow L~i+1~ - make justification work with indented blockquotes - add "ini ↦ conf-mode" to markdown-code-lang-modes [shortcut reference links]: http://spec.commonmark.org/0.27/#shortcut-reference-link ### rg-mode - make -project DTRT in dired ### page-break-lines - borked in magit-diff # XFCE - xfwm: hide/remove titlebar/decorations # Spell checkers - update dictionaries? # Conky Cannot use `${eval $${somefunc ${gw_iface}}}` more than once: conky.text = [[ ${eval ${gw_iface}} ${eval ${gw_iface}} ]] ⇒ wlp20 (null) See [GitHub issue](https://github.com/brndnmtthws/conky/issues/461).