Skip to content

Instantly share code, notes, and snippets.

@TakesxiSximada
Last active September 17, 2018 13:59
Show Gist options
  • Save TakesxiSximada/a0f4b17d35f95f6fbbacf87905702224 to your computer and use it in GitHub Desktop.
Save TakesxiSximada/a0f4b17d35f95f6fbbacf87905702224 to your computer and use it in GitHub Desktop.
markdown内のcode blockをpythonで1行ずつ実行する
;;; our-execblock.el --- Markdown code block execution helper for Emacs -*- lexical-binding: t -*-
;; Copyright (C) 2018 sximada
;; Author: sximada
;; Version: 1.0.0
;; Package-Version: 20180917.0001
;; Keywords: markdown
;; This program is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with this program. If not, see <http://www.gnu.org/licenses/>.
;;; Commentary:
;; Markdown code block execution helper for Emacs
;;; Code:
(setq lexical-binding t)
(require 'async-await)
(require 'dash)
(require 'generator)
(require 'promise)
(require 's)
(defvar our-execblock-execution-buffer "*Python*")
(defvar our-execblock-indent-regexp "^\\\s*")
(defun our-execblock-get-indent-count (line)
"Get indent count from string (one line)"
(length (car (s-match our-execblock-indent-regexp line))))
(defun our-execblock-ancillary-indent (line)
(let ((match (s-match "^\\(\\\s*\\)\\(def\\|class\\|async def\\)" line)))
(if (not match) line
(concat (nth 1 match) "\n" line))))
(defvar our-execblock-python-after-keywords
'("else"
"elif"
"except"
"finally"
))
(defun our-execblock-ancillary-new-line (line)
(let ((match (s-match "^\\([^\\\s]+\\)" line)))
(if (and
match
(not (-contains? our-execblock-python-after-keywords (s-chop-suffix ":" (nth 1 match)))))
(concat "\n" line)
line)))
(defun our-execblock-strip-indent (txt)
(with-current-buffer (get-buffer-create "*execblock*")
(erase-buffer)
(insert txt)
(perform-replace "^```.*" "" nil t nil nil nil 1 (point-max) nil)
(goto-char 0)
(delete-blank-lines)
(let ((indent-count (our-execblock-get-indent-count
(buffer-substring-no-properties 1 (point-at-eol)))))
(end-of-buffer)
(move-beginning-of-line 1)
(forward-char indent-count)
(delete-rectangle 1 (point)))
(delete-trailing-whitespace (point-min) (point-max))
(flush-lines "^\\s-*$" (point-min) (point-max) nil)
(let ((tmp (-reduce-from
(lambda (old new) (concat old "\n" new))
""
(mapcar
(lambda (line)
(-reduce-from (lambda (one-line fn) (funcall fn one-line))
line
'(our-execblock-ancillary-new-line
our-execblock-ancillary-indent)))
(s-lines (buffer-substring-no-properties (point-min) (point-max)))))))
(erase-buffer)
(insert tmp))
(goto-char (point-max))
(insert "\n")
(buffer-substring-no-properties (point-min) (point-max))))
(defun our-execblock-get-code-from-markdown ()
(interactive)
(our-execblock-set-no-echo)
(our-execblock-strip-indent
(apply 'buffer-substring-no-properties (or (markdown-get-enclosing-fenced-block-construct)
(markdown-code-block-at-point-p)))))
(defun our-execblock-detect-prompt-python (text)
"Return t for the Python prompt mark or continuation line mark"
(when (s-match "^[>\\.]\\{3\\}" text)
t))
(defun our-execblock-get-output-text (buf pos)
(with-current-buffer buf
(buffer-substring-no-properties pos (point-max))))
(iter-defun our-execblock-output-stream (buf line)
(iter-yield nil)
(let ((finished nil)
(output "")
(pos (with-current-buffer buf
(end-of-buffer)
(insert line)
(let ((p (point)))
(comint-send-input)
p))))
(while (not finished)
(iter-yield nil)
(setq output (our-execblock-get-output-text buf pos))
(if (our-execblock-detect-prompt-python output)
(progn
(setq finished t)
(iter-yield output))))))
(defun our-execblock-input (code)
(mapcar (lambda (line)
(our-execblock-output-stream (get-buffer our-execblock-execution-buffer) line))
(s-lines code)))
(defun our-sleep-async (n)
"Asynchronous wait."
(promise-new (lambda (resolve _reject)
(run-at-time n
nil
(lambda ()
(funcall resolve n))))))
(async-defun our-execblock-async (code)
(dolist (stream (our-execblock-input code))
(iter-do (output stream)
(await (our-sleep-async 0.2)))))
;;;###autoload
(defun our-execblock-set-no-echo ()
(interactive)
(setq-local comint-process-echoes t))
;;;###autoload
(defun our-execblock-select-buffer (&optional buf)
(interactive "bBuffer: ")
(setq our-execblock-execution-buffer (get-buffer buf)))
;;;###autoload
(defun our-execblock-markdown ()
(interactive)
(let ((code (our-execblock-get-code-from-markdown)))
(our-execblock-async code)))
(provide 'our-execblock)
;;; our-execblock.el ends here
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment