From 3da6e5174cbb3a2d551a9862dd79655908e2e0fc Mon Sep 17 00:00:00 2001 From: Artur Malabarba Date: Sun, 7 Dec 2014 01:15:37 +0000 Subject: Create sx-babel Has functions and a variable for font-locking pre blocks. --- sx-babel.el | 114 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 114 insertions(+) create mode 100644 sx-babel.el (limited to 'sx-babel.el') diff --git a/sx-babel.el b/sx-babel.el new file mode 100644 index 0000000..7da24a5 --- /dev/null +++ b/sx-babel.el @@ -0,0 +1,114 @@ +;;; sx-babel.el --- Font-locking pre blocks according to language. -*- lexical-binding: t; -*- + +;; Copyright (C) 2014 Artur Malabarba + +;; Author: Artur Malabarba + +;; 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 . + +;;; Commentary: + +;; This file contains functions and a variable for font-locking the +;; content of markdown pre blocks according to their language. The +;; main configuration point, for both the user and the developer is +;; the varuable `sx-babel-major-mode-alist', which see. + + +;;; Code: +(require 'sx-button) + +(defvar sx-babel-major-mode-alist + `((,(rx (or "*" "#+")) org-mode) + (,(rx (or "[" "(" ";" "#(")) emacs-lisp-mode)) + "List of cons cells determining which major-mode to use when. +Each car is a rule and each cdr is a major-mode. The first rule +which is satisfied activates the major-mode. + +Point is moved to the first non-blank character before testing +the rule, which can either be a string or a function. If it is a +string, is tested as a regexp starting from point. If it is a +function, is called with no arguments and should return non-nil +on a match.") +(put 'sx-babel-major-mode-alist 'risky-local-variable-p t) + + +;;; Font-locking the text +(defun sx-babel--make-pre-button (beg end) + "Turn the region between BEG and END into a button." + (let ((text (buffer-substring-no-properties beg end)) + indent) + (with-temp-buffer + (insert text) + (setq indent (sx-babel--unindent-buffer)) + (goto-char (point-min)) + (make-text-button + (point-min) (point-max) + 'sx-button-copy (buffer-string) + :type 'sx-question-mode-code-block) + (sx-babel--determine-and-activate-major-mode) + (font-lock-fontify-region (point-min) (point-max)) + (goto-char (point-min)) + (let ((space (make-string indent " "))) + (while (not (eobp)) + (insert space) + (forward-line 1))) + (setq text (buffer-string))) + (goto-char beg) + (delete-region beg end) + (insert text))) + +(defun sx-babel--determine-and-activate-major-mode () + "Activate the major-mode most suitable for the current buffer." + (let ((alist sx-babel-major-mode-alist) + cell) + (while (setq cell (pop alist)) + (goto-char (point-min)) + (skip-chars-forward "\r\n[:blank:]") + (let ((kar (car cell))) + (when (if (stringp kar) (looking-at kar) (funcall kar)) + (setq alist nil) + (funcall (cdr cell))))))) + +(defun sx-babel--unindent-buffer () + "Remove absolute indentation in current buffer. +Finds the least indented line, and removes that amount of +indentation from all lines. Primarily designed to extract the +content of markdown code blocks. + +Returns the amount of indentation removed." + (save-excursion + (goto-char (point-min)) + (let (result) + ;; Get indentation of each non-blank line + (while (null (eobp)) + (skip-chars-forward "[:blank:]") + (unless (looking-at "$") + (push (current-column) result)) + (forward-line 1)) + (when result + (setq result (apply #'min result)) + ;; Build a regexp with the smallest indentation + (let ((rx (format "^ \\{0,%s\\}" result))) + (goto-char (point-min)) + ;; Use this regexp to remove that much indentation + ;; throughout the buffer. + (while (and (null (eobp)) + (search-forward-regexp rx nil 'noerror)) + (replace-match "") + (forward-line 1)))) + (or result 0)))) + +(provide 'sx-babel) +;;; sx-babel.el ends here + -- cgit v1.2.3 From 635bbc2a3e410f5b97a3f20e5b790712cc873cc2 Mon Sep 17 00:00:00 2001 From: Artur Malabarba Date: Tue, 9 Dec 2014 14:13:31 +0000 Subject: Fix some implementation bugs --- sx-babel.el | 10 +++++++--- sx-question-print.el | 9 ++++----- 2 files changed, 11 insertions(+), 8 deletions(-) (limited to 'sx-babel.el') diff --git a/sx-babel.el b/sx-babel.el index 7da24a5..5544642 100644 --- a/sx-babel.el +++ b/sx-babel.el @@ -30,7 +30,11 @@ (defvar sx-babel-major-mode-alist `((,(rx (or "*" "#+")) org-mode) - (,(rx (or "[" "(" ";" "#(")) emacs-lisp-mode)) + (,(rx (or "[" "(" ";" "#(")) emacs-lisp-mode) + ;; @TODO: Make shell-mode work here. Currently errors because it + ;; needs a process. `sh-mode' isn't as nice. + (,(rx (or "$ " "# ")) sh-mode) + ) "List of cons cells determining which major-mode to use when. Each car is a rule and each cdr is a major-mode. The first rule which is satisfied activates the major-mode. @@ -59,7 +63,7 @@ on a match.") (sx-babel--determine-and-activate-major-mode) (font-lock-fontify-region (point-min) (point-max)) (goto-char (point-min)) - (let ((space (make-string indent " "))) + (let ((space (make-string indent ?\s))) (while (not (eobp)) (insert space) (forward-line 1))) @@ -78,7 +82,7 @@ on a match.") (let ((kar (car cell))) (when (if (stringp kar) (looking-at kar) (funcall kar)) (setq alist nil) - (funcall (cdr cell))))))) + (funcall (cadr cell))))))) (defun sx-babel--unindent-buffer () "Remove absolute indentation in current buffer. diff --git a/sx-question-print.el b/sx-question-print.el index 6b65d70..653ebab 100644 --- a/sx-question-print.el +++ b/sx-question-print.el @@ -436,11 +436,10 @@ font-locking." (setq beg (point)))) (setq end (point)) (sx-babel--make-pre-button - (buffer-substring - (save-excursion - (goto-char beg) - (line-beginning-position)) - end))))) + (save-excursion + (goto-char beg) + (line-beginning-position)) + end)))) (provide 'sx-question-print) ;;; sx-question-print.el ends here -- cgit v1.2.3 From 2171ad472e1c5180bb9ac021197db04d94f3c078 Mon Sep 17 00:00:00 2001 From: Artur Malabarba Date: Tue, 16 Dec 2014 20:52:23 -0200 Subject: delay-mode-hooks on code blocks --- sx-babel.el | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) (limited to 'sx-babel.el') diff --git a/sx-babel.el b/sx-babel.el index 5544642..b4ff306 100644 --- a/sx-babel.el +++ b/sx-babel.el @@ -56,11 +56,16 @@ on a match.") (insert text) (setq indent (sx-babel--unindent-buffer)) (goto-char (point-min)) - (make-text-button - (point-min) (point-max) - 'sx-button-copy (buffer-string) - :type 'sx-question-mode-code-block) - (sx-babel--determine-and-activate-major-mode) + (let ((mode (sx-babel--determine-major-mode))) + (make-text-button + (point-min) (point-max) + 'sx-button-copy (buffer-string) + ;; We store the mode here so it can be used if the user wants + ;; to edit the code block. + 'sx-mode mode + :type 'sx-question-mode-code-block) + (when mode + (delay-mode-hooks (funcall mode)))) (font-lock-fontify-region (point-min) (point-max)) (goto-char (point-min)) (let ((space (make-string indent ?\s))) @@ -72,17 +77,18 @@ on a match.") (delete-region beg end) (insert text))) -(defun sx-babel--determine-and-activate-major-mode () - "Activate the major-mode most suitable for the current buffer." +(defun sx-babel--determine-major-mode () + "Return the major-mode most suitable for the current buffer." (let ((alist sx-babel-major-mode-alist) - cell) + cell out) (while (setq cell (pop alist)) (goto-char (point-min)) (skip-chars-forward "\r\n[:blank:]") (let ((kar (car cell))) (when (if (stringp kar) (looking-at kar) (funcall kar)) (setq alist nil) - (funcall (cadr cell))))))) + (setq out (cadr cell))))) + out)) (defun sx-babel--unindent-buffer () "Remove absolute indentation in current buffer. -- cgit v1.2.3 From c3d6d1f689598940f29f19c328e10d7c5fff0ade Mon Sep 17 00:00:00 2001 From: Artur Malabarba Date: Tue, 16 Dec 2014 21:20:31 -0200 Subject: Make entire code-block a single button This fixes a bug we had. Hitting TAB on a codeblock would move us to the next line on the code block, instead of going to another button. Now the entire code block is a single button, so that is fixed. --- sx-babel.el | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) (limited to 'sx-babel.el') diff --git a/sx-babel.el b/sx-babel.el index b4ff306..24e56c2 100644 --- a/sx-babel.el +++ b/sx-babel.el @@ -51,31 +51,31 @@ on a match.") (defun sx-babel--make-pre-button (beg end) "Turn the region between BEG and END into a button." (let ((text (buffer-substring-no-properties beg end)) - indent) + indent mode copy) (with-temp-buffer (insert text) (setq indent (sx-babel--unindent-buffer)) (goto-char (point-min)) - (let ((mode (sx-babel--determine-major-mode))) - (make-text-button - (point-min) (point-max) - 'sx-button-copy (buffer-string) - ;; We store the mode here so it can be used if the user wants - ;; to edit the code block. - 'sx-mode mode - :type 'sx-question-mode-code-block) - (when mode - (delay-mode-hooks (funcall mode)))) + (setq mode (sx-babel--determine-major-mode)) + (setq copy (string-trim-right (buffer-string))) + (when mode + (delay-mode-hooks (funcall mode))) (font-lock-fontify-region (point-min) (point-max)) (goto-char (point-min)) (let ((space (make-string indent ?\s))) (while (not (eobp)) - (insert space) + (insert-and-inherit space) (forward-line 1))) (setq text (buffer-string))) (goto-char beg) (delete-region beg end) - (insert text))) + (insert-text-button + text + 'sx-button-copy copy + ;; We store the mode here so it can be used if the user wants + ;; to edit the code block. + 'sx-mode mode + :type 'sx-question-mode-code-block))) (defun sx-babel--determine-major-mode () "Return the major-mode most suitable for the current buffer." -- cgit v1.2.3 From d7ebf1515548e3bb01612fabba5de5d68a783f23 Mon Sep 17 00:00:00 2001 From: Sean Allred Date: Sat, 20 Dec 2014 03:13:47 -0500 Subject: Hotfix require subr-x For `string-trim-right' --- sx-babel.el | 1 + 1 file changed, 1 insertion(+) (limited to 'sx-babel.el') diff --git a/sx-babel.el b/sx-babel.el index 24e56c2..7346f99 100644 --- a/sx-babel.el +++ b/sx-babel.el @@ -26,6 +26,7 @@ ;;; Code: +(require 'subr-x) (require 'sx-button) (defvar sx-babel-major-mode-alist -- cgit v1.2.3 From 30eeaaad19858edb4543d60772b93adb7e7736be Mon Sep 17 00:00:00 2001 From: Artur Malabarba Date: Sat, 20 Dec 2014 15:10:08 -0200 Subject: Hotfix subr-x didn't exist before 24.3 --- sx-babel.el | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'sx-babel.el') diff --git a/sx-babel.el b/sx-babel.el index 7346f99..b30a044 100644 --- a/sx-babel.el +++ b/sx-babel.el @@ -26,7 +26,6 @@ ;;; Code: -(require 'subr-x) (require 'sx-button) (defvar sx-babel-major-mode-alist @@ -58,7 +57,7 @@ on a match.") (setq indent (sx-babel--unindent-buffer)) (goto-char (point-min)) (setq mode (sx-babel--determine-major-mode)) - (setq copy (string-trim-right (buffer-string))) + (setq copy (replace-regexp-in-string "[[:space:]]+\\'" "" (buffer-string))) (when mode (delay-mode-hooks (funcall mode))) (font-lock-fontify-region (point-min) (point-max)) -- cgit v1.2.3