-
-
Notifications
You must be signed in to change notification settings - Fork 184
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Interactive markdown #1304
Open
garlic0x1
wants to merge
22
commits into
lem-project:main
Choose a base branch
from
garlic0x1:interactive-markdown
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Interactive markdown #1304
Changes from all commits
Commits
Show all changes
22 commits
Select commit
Hold shift + click to select a range
227802f
interactive markdown
garlic0x1 64be4e5
eval-block-and-insert
garlic0x1 f219d9d
delete old result on insert
garlic0x1 4157854
kill-block-eval-result command
garlic0x1 6cc8a96
keybindings
garlic0x1 ca28c11
ensure markdown mode
garlic0x1 4e36d99
bugfix
garlic0x1 d54c2a2
kinda fixed kill and eval
garlic0x1 58f11c5
add message and clean up
garlic0x1 186633a
export register macro and remove extra with-constant's
garlic0x1 43a071a
retry tests
garlic0x1 a897c62
delay read-from-string for micros env
garlic0x1 069481e
simplify lambda/funcall
garlic0x1 477139b
vindarel style
garlic0x1 2964a95
add prefixes to commands
garlic0x1 384abd3
delete copied points
garlic0x1 fa32311
eval and do nothing command
garlic0x1 8983947
docstrings
garlic0x1 91b679f
dedupe cleanup logic and mode check
garlic0x1 00f20d9
unify handler wrappers
garlic0x1 250adf5
s/prog1/unwind-protect
garlic0x1 fa78169
wtf
garlic0x1 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,140 @@ | ||
(defpackage :lem-markdown-mode/interactive | ||
(:use :cl :lem) | ||
(:import-from #:alexandria :if-let :when-let) | ||
(:export :register-block-evaluator)) | ||
(in-package :lem-markdown-mode/interactive) | ||
|
||
(define-keys lem-markdown-mode::*markdown-mode-keymap* | ||
("C-c C-e" 'markdown-eval-block) | ||
("C-c C-r" 'markdown-eval-block-nop) | ||
("C-c C-c" 'markdown-eval-block-and-insert) | ||
("C-c C-d" 'markdown-kill-block-result)) | ||
|
||
(defvar *block-evaluators* (make-hash-table :test #'equal) | ||
"Dispatch table for block evaluators per language.") | ||
|
||
(defmacro register-block-evaluator (language (string callback) &body body) | ||
"Convenience macro to register block evaluators, wraps setf." | ||
`(setf (gethash ,language *block-evaluators*) | ||
(lambda (,string ,callback) | ||
,@body))) | ||
|
||
(defmacro with-constant-position ((point) &body body) | ||
"This allows you to move around the point without worry." | ||
`(let ((tmp (copy-point ,point))) | ||
(unwind-protect (progn ,@body) | ||
(move-point ,point tmp) | ||
(delete-point tmp)))) | ||
|
||
(defmacro when-markdown-mode (&body body) | ||
"Ensure the major mode is markdown-mode and alert the user if not." | ||
`(if (eq 'lem-markdown-mode:markdown-mode | ||
(buffer-major-mode (current-buffer))) | ||
(progn ,@body) | ||
(message "Not in markdown mode."))) | ||
|
||
(defun pop-up-buffer (name text) | ||
"Create a pop-up with name containing text." | ||
(let ((buffer (make-buffer name))) | ||
(erase-buffer buffer) | ||
(with-buffer-read-only buffer nil | ||
(insert-string (buffer-point buffer) text) | ||
(with-pop-up-typeout-window (s buffer) | ||
(declare (ignore s)))))) | ||
|
||
(defun block-fence-lang (fence) | ||
"Get language from a block fence string." | ||
(let ((str (coerce (cdddr (coerce fence 'list)) 'string))) | ||
(unless (str:emptyp str) | ||
str))) | ||
|
||
(defun block-at-point (point) | ||
"Get the language of a code block and its contents." | ||
(search-backward-regexp point "```") | ||
(when-let ((lang (block-fence-lang (str:trim (line-string point))))) | ||
(search-forward point (format nil "~%")) | ||
(let ((start (copy-point point))) | ||
(search-forward-regexp point "```") | ||
(search-backward point (format nil "~%")) | ||
(let ((string (points-to-string start point))) | ||
(delete-point start) | ||
(values lang string))))) | ||
|
||
(define-command markdown-kill-block-result (&optional (point (current-point))) () | ||
"Searches for a result block below the current code block, and kills it." | ||
(when-markdown-mode | ||
(with-constant-position (point) | ||
(when (block-at-point point) | ||
(search-forward-regexp point "```") | ||
(line-offset point 2) | ||
(when (equal "result" (block-fence-lang (line-string point))) | ||
(loop :while (not (equal "```" (line-string point))) | ||
:do (kill-whole-line) | ||
:do (line-offset point 1)) | ||
(kill-whole-line) | ||
(kill-whole-line)))))) | ||
|
||
(defun pop-up-eval-result (point result) | ||
"Display results of evaluation in a pop-up buffer." | ||
(declare (ignore point)) | ||
(pop-up-buffer "*result*" (format nil "~a" result))) | ||
|
||
(defun insert-eval-result (point result) | ||
"Insert results of evaluation in a code block." | ||
(block-at-point point) | ||
(search-forward-regexp point "```") | ||
(insert-string point (format nil "~%~%```result~%~a~%```" result)) | ||
(message "Block evaluated.")) | ||
|
||
(defun nop-eval-result (point result) | ||
"Clean up and do nothing with result." | ||
(declare (ignore point result)) | ||
(message "Block evaluated.")) | ||
|
||
(defun wrap-handler (handler point) | ||
"Wrap handlers to capture and delete the point when they are done." | ||
(lambda (result) | ||
(funcall handler point result) | ||
(delete-point point))) | ||
|
||
(defun eval-block-internal (point handler) | ||
"Evaluate code block and apply handler to result." | ||
(when-markdown-mode | ||
(multiple-value-bind (lang block) (block-at-point point) | ||
(when lang | ||
(if-let ((evaluator (gethash lang *block-evaluators*))) | ||
(funcall evaluator block (wrap-handler handler point)) | ||
(message "No evaluator registered for ~a." lang)))))) | ||
|
||
(define-command markdown-eval-block () () | ||
"Evaluate current markdown code block and display results in pop-up." | ||
(eval-block-internal (copy-point (current-point)) #'pop-up-eval-result)) | ||
|
||
(define-command markdown-eval-block-nop () () | ||
"Evaluate current markdown code block and do nothing with result." | ||
(eval-block-internal (copy-point (current-point)) #'nop-eval-result)) | ||
|
||
(define-command markdown-eval-block-and-insert () () | ||
"Evaluate current markdown code block and display results in pop-up." | ||
(markdown-kill-block-result) | ||
(eval-block-internal (copy-point (current-point)) #'insert-eval-result)) | ||
|
||
;; | ||
;; Default evaluators: | ||
;; | ||
|
||
(register-block-evaluator "bash" (string callback) | ||
"Register evaluator for Bash blocks." | ||
(bt:make-thread | ||
(lambda () | ||
(funcall callback (uiop:run-program string :output :string))))) | ||
|
||
(register-block-evaluator "lisp" (string callback) | ||
"Register evaluator for Lisp blocks." | ||
(lem-lisp-mode:check-connection) | ||
(lem-lisp-mode:lisp-eval-async | ||
(read-from-string (format nil "(progn ~a)" string)) | ||
callback)) | ||
|
||
;; `(handler-case (eval (read-from-string (format nil "(progn ~a)" ,string))) | ||
;; (error (c) (format nil "Error: ~a" c))) |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,5 @@ | ||
(defsystem "lem-markdown-mode" | ||
:depends-on ("lem") | ||
:serial t | ||
:components ((:file "markdown-mode"))) | ||
:components ((:file "markdown-mode") | ||
(:file "interactive"))) |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did you know of
with-point(s)
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Doesn't seem to work the same, I will play around with it for a bit though and see if I can get it to work.
I tried to replace
with
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you don't call delete-point for copy-point, the memory leaks.