scribe.el 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328
  1. ;;; scribe.el --- scribe mode, and its idiosyncratic commands
  2. ;; Copyright (C) 1985, 2001-2012 Free Software Foundation, Inc.
  3. ;; Author: William Sommerfeld
  4. ;; (according to ack.texi)
  5. ;; Maintainer: FSF
  6. ;; Keywords: wp
  7. ;; Obsolete-since: 22.1
  8. ;; This file is part of GNU Emacs.
  9. ;; GNU Emacs is free software: you can redistribute it and/or modify
  10. ;; it under the terms of the GNU General Public License as published by
  11. ;; the Free Software Foundation, either version 3 of the License, or
  12. ;; (at your option) any later version.
  13. ;; GNU Emacs is distributed in the hope that it will be useful,
  14. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. ;; GNU General Public License for more details.
  17. ;; You should have received a copy of the GNU General Public License
  18. ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
  19. ;;; Commentary:
  20. ;; A major mode for editing source in written for the Scribe text formatter.
  21. ;; Knows about Scribe syntax and standard layout rules. The command to
  22. ;; run Scribe on a buffer is bogus; someone interested should fix it.
  23. ;;; Code:
  24. (defvar compile-command)
  25. (defgroup scribe nil
  26. "Scribe mode."
  27. :prefix "scribe-"
  28. :group 'wp)
  29. (defvar scribe-mode-syntax-table nil
  30. "Syntax table used while in scribe mode.")
  31. (defvar scribe-mode-abbrev-table nil
  32. "Abbrev table used while in scribe mode.")
  33. (defcustom scribe-fancy-paragraphs nil
  34. "*Non-nil makes Scribe mode use a different style of paragraph separation."
  35. :type 'boolean
  36. :group 'scribe)
  37. (defcustom scribe-electric-quote nil
  38. "*Non-nil makes insert of double quote use `` or '' depending on context."
  39. :type 'boolean
  40. :group 'scribe)
  41. (defcustom scribe-electric-parenthesis nil
  42. "*Non-nil makes parenthesis char ( (]}> ) automatically insert its close
  43. if typed after an @Command form."
  44. :type 'boolean
  45. :group 'scribe)
  46. (defconst scribe-open-parentheses "[({<"
  47. "Open parenthesis characters for Scribe.")
  48. (defconst scribe-close-parentheses "])}>"
  49. "Close parenthesis characters for Scribe.
  50. These should match up with `scribe-open-parenthesis'.")
  51. (if (null scribe-mode-syntax-table)
  52. (let ((st (syntax-table)))
  53. (unwind-protect
  54. (progn
  55. (setq scribe-mode-syntax-table (copy-syntax-table
  56. text-mode-syntax-table))
  57. (set-syntax-table scribe-mode-syntax-table)
  58. (modify-syntax-entry ?\" " ")
  59. (modify-syntax-entry ?\\ " ")
  60. (modify-syntax-entry ?@ "w ")
  61. (modify-syntax-entry ?< "(> ")
  62. (modify-syntax-entry ?> ")< ")
  63. (modify-syntax-entry ?[ "(] ")
  64. (modify-syntax-entry ?] ")[ ")
  65. (modify-syntax-entry ?{ "(} ")
  66. (modify-syntax-entry ?} "){ ")
  67. (modify-syntax-entry ?' "w "))
  68. (set-syntax-table st))))
  69. (defvar scribe-mode-map nil)
  70. (if scribe-mode-map
  71. nil
  72. (setq scribe-mode-map (make-sparse-keymap))
  73. (define-key scribe-mode-map "\t" 'scribe-tab)
  74. (define-key scribe-mode-map "\e\t" 'tab-to-tab-stop)
  75. (define-key scribe-mode-map "\es" 'center-line)
  76. (define-key scribe-mode-map "\e}" 'up-list)
  77. (define-key scribe-mode-map "\eS" 'center-paragraph)
  78. (define-key scribe-mode-map "\"" 'scribe-insert-quote)
  79. (define-key scribe-mode-map "(" 'scribe-parenthesis)
  80. (define-key scribe-mode-map "[" 'scribe-parenthesis)
  81. (define-key scribe-mode-map "{" 'scribe-parenthesis)
  82. (define-key scribe-mode-map "<" 'scribe-parenthesis)
  83. (define-key scribe-mode-map "\C-c\C-c" 'scribe-chapter)
  84. (define-key scribe-mode-map "\C-c\C-t" 'scribe-section)
  85. (define-key scribe-mode-map "\C-c\C-s" 'scribe-subsection)
  86. (define-key scribe-mode-map "\C-c\C-v" 'scribe-insert-environment)
  87. (define-key scribe-mode-map "\C-c\C-e" 'scribe-bracket-region-be)
  88. (define-key scribe-mode-map "\C-c[" 'scribe-begin)
  89. (define-key scribe-mode-map "\C-c]" 'scribe-end)
  90. (define-key scribe-mode-map "\C-c\C-i" 'scribe-italicize-word)
  91. (define-key scribe-mode-map "\C-c\C-b" 'scribe-bold-word)
  92. (define-key scribe-mode-map "\C-c\C-u" 'scribe-underline-word))
  93. ;;;###autoload
  94. (define-derived-mode scribe-mode text-mode "Scribe"
  95. "Major mode for editing files of Scribe (a text formatter) source.
  96. Scribe-mode is similar to text-mode, with a few extra commands added.
  97. \\{scribe-mode-map}
  98. Interesting variables:
  99. `scribe-fancy-paragraphs'
  100. Non-nil makes Scribe mode use a different style of paragraph separation.
  101. `scribe-electric-quote'
  102. Non-nil makes insert of double quote use `` or '' depending on context.
  103. `scribe-electric-parenthesis'
  104. Non-nil makes an open-parenthesis char (one of `([<{')
  105. automatically insert its close if typed after an @Command form."
  106. (set (make-local-variable 'comment-start) "@Comment[")
  107. (set (make-local-variable 'comment-start-skip) (concat "@Comment[" scribe-open-parentheses "]"))
  108. (set (make-local-variable 'comment-column) 0)
  109. (set (make-local-variable 'comment-end) "]")
  110. (set (make-local-variable 'paragraph-start)
  111. (concat "\\([\n\f]\\)\\|\\(@\\w+["
  112. scribe-open-parentheses
  113. "].*["
  114. scribe-close-parentheses
  115. "]$\\)"))
  116. (set (make-local-variable 'paragraph-separate)
  117. (if scribe-fancy-paragraphs paragraph-start "$"))
  118. (set (make-local-variable 'sentence-end)
  119. "\\([.?!]\\|@:\\)[]\"')}]*\\($\\| $\\|\t\\| \\)[ \t\n]*")
  120. (set (make-local-variable 'compile-command)
  121. (concat "scribe " (buffer-file-name))))
  122. (defun scribe-tab ()
  123. (interactive)
  124. (insert "@\\"))
  125. ;; This algorithm could probably be improved somewhat.
  126. ;; Right now, it loses seriously...
  127. (defun scribe ()
  128. "Run Scribe on the current buffer."
  129. (interactive)
  130. (call-interactively 'compile))
  131. (defun scribe-envelop-word (string count)
  132. "Surround current word with Scribe construct @STRING[...].
  133. COUNT specifies how many words to surround. A negative count means
  134. to skip backward."
  135. (let ((spos (point)) (epos (point)) (ccoun 0) noparens)
  136. (if (not (zerop count))
  137. (progn (if (= (char-syntax (preceding-char)) ?w)
  138. (forward-sexp (min -1 count)))
  139. (setq spos (point))
  140. (if (looking-at (concat "@\\w[" scribe-open-parentheses "]"))
  141. (forward-char 2)
  142. (goto-char epos)
  143. (skip-chars-backward "\\W")
  144. (forward-char -1))
  145. (forward-sexp (max count 1))
  146. (setq epos (point))))
  147. (goto-char spos)
  148. (while (and (< ccoun (length scribe-open-parentheses))
  149. (save-excursion
  150. (or (search-forward (char-to-string
  151. (aref scribe-open-parentheses ccoun))
  152. epos t)
  153. (search-forward (char-to-string
  154. (aref scribe-close-parentheses ccoun))
  155. epos t)))
  156. (setq ccoun (1+ ccoun))))
  157. (if (>= ccoun (length scribe-open-parentheses))
  158. (progn (goto-char epos)
  159. (insert "@end(" string ")")
  160. (goto-char spos)
  161. (insert "@begin(" string ")"))
  162. (goto-char epos)
  163. (insert (aref scribe-close-parentheses ccoun))
  164. (goto-char spos)
  165. (insert "@" string (aref scribe-open-parentheses ccoun))
  166. (goto-char epos)
  167. (forward-char 3)
  168. (skip-chars-forward scribe-close-parentheses))))
  169. (defun scribe-underline-word (count)
  170. "Underline COUNT words around point by means of Scribe constructs."
  171. (interactive "p")
  172. (scribe-envelop-word "u" count))
  173. (defun scribe-bold-word (count)
  174. "Boldface COUNT words around point by means of Scribe constructs."
  175. (interactive "p")
  176. (scribe-envelop-word "b" count))
  177. (defun scribe-italicize-word (count)
  178. "Italicize COUNT words around point by means of Scribe constructs."
  179. (interactive "p")
  180. (scribe-envelop-word "i" count))
  181. (defun scribe-begin ()
  182. (interactive)
  183. (insert "\n")
  184. (forward-char -1)
  185. (scribe-envelop-word "Begin" 0)
  186. (re-search-forward (concat "[" scribe-open-parentheses "]")))
  187. (defun scribe-end ()
  188. (interactive)
  189. (insert "\n")
  190. (forward-char -1)
  191. (scribe-envelop-word "End" 0)
  192. (re-search-forward (concat "[" scribe-open-parentheses "]")))
  193. (defun scribe-chapter ()
  194. (interactive)
  195. (insert "\n")
  196. (forward-char -1)
  197. (scribe-envelop-word "Chapter" 0)
  198. (re-search-forward (concat "[" scribe-open-parentheses "]")))
  199. (defun scribe-section ()
  200. (interactive)
  201. (insert "\n")
  202. (forward-char -1)
  203. (scribe-envelop-word "Section" 0)
  204. (re-search-forward (concat "[" scribe-open-parentheses "]")))
  205. (defun scribe-subsection ()
  206. (interactive)
  207. (insert "\n")
  208. (forward-char -1)
  209. (scribe-envelop-word "SubSection" 0)
  210. (re-search-forward (concat "[" scribe-open-parentheses "]")))
  211. (defun scribe-bracket-region-be (env min max)
  212. (interactive "sEnvironment: \nr")
  213. (save-excursion
  214. (goto-char max)
  215. (insert "@end(" env ")\n")
  216. (goto-char min)
  217. (insert "@begin(" env ")\n")))
  218. (defun scribe-insert-environment (env)
  219. (interactive "sEnvironment: ")
  220. (scribe-bracket-region-be env (point) (point))
  221. (forward-line 1)
  222. (insert ?\n)
  223. (forward-char -1))
  224. (defun scribe-insert-quote (count)
  225. "Insert ``, '' or \" according to preceding character.
  226. If `scribe-electric-quote' is non-nil, insert ``, '' or \" according
  227. to preceding character. With numeric arg N, always insert N \" characters.
  228. Else just insert \"."
  229. (interactive "P")
  230. (if (or count (not scribe-electric-quote))
  231. (self-insert-command (prefix-numeric-value count))
  232. (let (lastfore lastback lastquote)
  233. (insert
  234. (cond
  235. ((= (preceding-char) ?\\) ?\")
  236. ((bobp) "``")
  237. (t
  238. (setq lastfore (save-excursion (and (search-backward
  239. "``" (- (point) 1000) t)
  240. (point)))
  241. lastback (save-excursion (and (search-backward
  242. "''" (- (point) 1000) t)
  243. (point)))
  244. lastquote (save-excursion (and (search-backward
  245. "\"" (- (point) 100) t)
  246. (point))))
  247. (if (not lastquote)
  248. (cond ((not lastfore) "``")
  249. ((not lastback) "''")
  250. ((> lastfore lastback) "''")
  251. (t "``"))
  252. (cond ((and (not lastback) (not lastfore)) "\"")
  253. ((and lastback (not lastfore) (> lastquote lastback)) "\"")
  254. ((and lastback (not lastfore) (> lastback lastquote)) "``")
  255. ((and lastfore (not lastback) (> lastquote lastfore)) "\"")
  256. ((and lastfore (not lastback) (> lastfore lastquote)) "''")
  257. ((and (> lastquote lastfore) (> lastquote lastback)) "\"")
  258. ((> lastfore lastback) "''")
  259. (t "``")))))))))
  260. (defun scribe-parenthesis (count)
  261. "If scribe-electric-parenthesis is non-nil, insertion of an open-parenthesis
  262. character inserts the following close parenthesis character if the
  263. preceding text is of the form @Command."
  264. (interactive "P")
  265. (self-insert-command (prefix-numeric-value count))
  266. (let (at-command paren-char point-save)
  267. (if (or count (not scribe-electric-parenthesis))
  268. nil
  269. (save-excursion
  270. (forward-char -1)
  271. (setq point-save (point))
  272. (skip-chars-backward (concat "^ \n\t\f" scribe-open-parentheses))
  273. (setq at-command (and (equal (following-char) ?@)
  274. (/= (point) (1- point-save)))))
  275. (if (and at-command
  276. (setq paren-char
  277. (string-match (regexp-quote
  278. (char-to-string (preceding-char)))
  279. scribe-open-parentheses)))
  280. (save-excursion
  281. (insert (aref scribe-close-parentheses paren-char)))))))
  282. (provide 'scribe)
  283. ;;; scribe.el ends here