Last active
January 17, 2020 02:44
-
-
Save antifuchs/aa9fa4c3d1354ea163bc13e63d32db1a to your computer and use it in GitHub Desktop.
This sets up a key binding for C-c ' in rust-mode, which acts very similarly to org-src's key binding, except the other direction: If you use it on a rustdoc comment, it'll open another buffer with the comment in it, in markdown-mode.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
;;; Copyright (C) 2018, 2019 Andreas Fuchs <asf@boinkor.net> | |
;;; Made available to you under the terms of GPLv2 or later: https://choosealicense.com/licenses/gpl-2.0/ | |
(use-package edit-indirect | |
:straight t) | |
(defconst asf--rustdoc-line-prefixes (concat "^\\([\t ]*" (regexp-opt '("///" "//!")) "\\)")) | |
(defun asf--rustdoc-current-comment-block-region () | |
(save-excursion | |
(forward-line 0) | |
(when (looking-at asf--rustdoc-line-prefixes) | |
;; determine the current line's prefix & extract all the lines | |
;; with matching prefixes that surround it (we assume that's the | |
;; extent of the rustdoc block): | |
(let ((prefix (match-string-no-properties 1)) | |
(initial-position (point)) | |
start end) | |
;; look back: | |
(while (and (looking-at prefix) | |
(not (eql (point) (point-min)))) | |
(setq start (point)) | |
(forward-line -1)) | |
(when (looking-at prefix) | |
;; we're at the beginning of the buffer; make sure we got that: | |
(setq start (point))) | |
(goto-char initial-position) | |
(while (and (not (eql (point) (point-max))) | |
(looking-at prefix)) | |
(forward-line 1) | |
(setq end (point))) | |
(list start end))))) | |
(defvar asf--rustdoc-prefix) | |
(defun asf--rustdoc-prefix-without-space (prefix) | |
(replace-regexp-in-string "[\t ]*$" "" prefix)) | |
(defun asf--rustdoc-strip-prefix () | |
(save-excursion | |
(goto-char (point-min)) | |
;; infer prefix from first line: | |
(let* ((prefix (when (looking-at (concat asf--rustdoc-line-prefixes "[\t ]*")) | |
(match-string 0))) | |
(prefix-re (concat "^" prefix)) | |
(empty-line-prefix-re (concat "^" (asf--rustdoc-prefix-without-space prefix)))) | |
(while (< (point) (point-max)) | |
(when (or (looking-at prefix-re) | |
(looking-at empty-line-prefix-re)) | |
(replace-match "") | |
(forward-line 1))) | |
prefix))) | |
(defun asf--rustdoc-apply-prefix () | |
(let ((prefix asf--rustdoc-prefix)) | |
(save-excursion | |
(goto-char (point-min)) | |
(while (and (re-search-forward "^" nil t) | |
(not (eql (point) (point-max)))) | |
(replace-match prefix " ")) | |
(goto-char (point-max)) | |
;; non-empty lines at the end must end in a newline: | |
(unless (looking-at "^$") | |
(insert "\n"))))) | |
(defun asf--rustdoc-setup-buffer () | |
;; Strip the comment prefix from lines & set up the buffer's major mode: | |
(let ((prefix (asf--rustdoc-strip-prefix))) | |
(markdown-mode) | |
(setq-local asf--rustdoc-prefix prefix) | |
(setq-local edit-indirect-before-commit-hook '(asf--rustdoc-apply-prefix)))) | |
(defun asf-rustdoc-edit () | |
(interactive) | |
(let ((guess (asf--rustdoc-current-comment-block-region))) | |
(unless guess | |
(error "Not in a rustdoc comment that I can guess!")) | |
(destructuring-bind (start end) guess | |
(let ((edit-indirect-after-creation-hook 'asf--rustdoc-setup-buffer)) | |
(edit-indirect-region start end t))))) | |
(add-hook 'rust-mode-hook | |
(defun asf--rustdoc-setup-hook () | |
(bind-key "C-c '" 'asf-rustdoc-edit rust-mode-map))) |
@shepmaster I think instead of (bind-key "C-c '" 'asf-rustdoc-edit rust-mode-map)
you should use (define-key rust-mode-map (kbd "C-c '") 'asf-rustdoc-edit)
On line 57, if you insert inside the while loop the following code it prevents empty lines from ending in spaces:
(when (eolp)
(delete-horizontal-space))
Making it
(while (and (re-search-forward "^" nil t)
(not (eql (point) (point-max))))
(replace-match prefix " ")
(when (eolp)
(delete-horizontal-space)))
These improvements and more are tracked in my emacs config
https://github.com/twlz0ne/comment-edit.el is a better package
Huh, that's really cool - glad somebody a real package that did what this was intended to do.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This is (would be) wonderful, but there's a handful of non-standard (?) functions used here:
use-package
bind-key
destructuring-bind
(this is where I stoped to post this comment 😄 )At least, these all seemed to be missing in my Emacs 26.1 install.
Is there any chance of some modifications to list the dependencies or work in "stock" Emacs?
I'm using this for now:
Once in the Markdown mode, I use polymode to edit the inline examples as Rust again (very meta).