ein-multilang.el 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. ;;; ein-multilang.el --- Notebook mode with multiple language fontification
  2. ;; Copyright (C) 2012 Takafumi Arakaki
  3. ;; Author: Takafumi Arakaki <aka.tkf at gmail.com>
  4. ;; This file is NOT part of GNU Emacs.
  5. ;; ein-multilang.el is free software: you can redistribute it and/or modify
  6. ;; it under the terms of the GNU General Public License as published by
  7. ;; the Free Software Foundation, either version 3 of the License, or
  8. ;; (at your option) any later version.
  9. ;; ein-multilang.el is distributed in the hope that it will be useful,
  10. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. ;; GNU General Public License for more details.
  13. ;; You should have received a copy of the GNU General Public License
  14. ;; along with ein-multilang.el.
  15. ;; If not, see <http://www.gnu.org/licenses/>.
  16. ;;; Commentary:
  17. ;;
  18. ;;; Code:
  19. (eval-when-compile (require 'cl))
  20. (eval-when-compile (defvar markdown-mode-map))
  21. (require 'ein-worksheet)
  22. (require 'ein-multilang-fontify)
  23. (defun ein:ml-fontify (limit)
  24. "Fontify next input area comes after the current point then
  25. return `t' or `nil' if not found.
  26. See info node `(elisp) Search-based Fontification'."
  27. (ein:log-ignore-errors
  28. (ein:ml-fontify-1 limit)))
  29. (defun ein:ml-current-or-next-input-cell (ewoc-node)
  30. "Almost identical to `ein:worksheet-next-input-cell' but return
  31. the current cell if EWOC-NODE is the input area node."
  32. (let* ((ewoc-data (ewoc-data ewoc-node))
  33. (cell (ein:$node-data ewoc-data))
  34. (path (ein:$node-path ewoc-data))
  35. (element (nth 1 path)))
  36. (if (memql element '(prompt input))
  37. cell
  38. (ein:cell-next cell))))
  39. (defun ein:ml-fontify-1 (limit)
  40. "Actual implementation of `ein:ml-fontify'.
  41. This function may raise an error."
  42. (ein:and-let* ((pos (point))
  43. (node (ein:worksheet-get-nearest-cell-ewoc-node pos limit))
  44. (cell (ein:ml-current-or-next-input-cell node))
  45. (start (ein:cell-input-pos-min cell))
  46. (end (ein:cell-input-pos-max cell))
  47. ((<= end limit))
  48. ((< start end))
  49. (lang (ein:cell-language cell)))
  50. (let ((inhibit-read-only t))
  51. (ein:mlf-font-lock-fontify-block lang start end)
  52. ;; Emacs fontification mechanism requires the function to move
  53. ;; the point. Do *not* use `(goto-char end)'. As END is in the
  54. ;; input area, fontification falls into an infinite loop.
  55. (ewoc-goto-node (oref cell :ewoc) (ein:cell-element-get cell :footer)))
  56. t))
  57. (defun ein:ml-back-to-prev-node ()
  58. (ein:aand (ein:worksheet-get-ewoc) (ewoc-goto-prev it 1)))
  59. (defvar ein:ml-font-lock-keywords
  60. '((ein:ml-fontify))
  61. "Default `font-lock-keywords' for `ein:notebook-multilang-mode'.")
  62. (defun ein:ml-set-font-lock-defaults ()
  63. (set (make-local-variable 'font-lock-defaults)
  64. '(ein:ml-font-lock-keywords
  65. ;; The following are adapted from org-mode but I am not sure
  66. ;; if I need them:
  67. t nil nil
  68. ein:ml-back-to-prev-node)))
  69. ;;;###autoload
  70. (define-derived-mode ein:notebook-multilang-mode fundamental-mode "ein:ml"
  71. "Notebook mode with multiple language fontification."
  72. (make-local-variable 'comment-start)
  73. (make-local-variable 'comment-start-skip)
  74. (make-local-variable 'parse-sexp-lookup-properties)
  75. (make-local-variable 'parse-sexp-ignore-comments)
  76. (make-local-variable 'indent-line-function)
  77. (make-local-variable 'indent-region-function)
  78. (make-local-variable 'beginning-of-defun-function)
  79. (make-local-variable 'end-of-defun-function)
  80. (setq beginning-of-defun-function 'ein:worksheet-beginning-of-cell-input)
  81. (setq end-of-defun-function 'ein:worksheet-end-of-cell-input)
  82. (ein:ml-lang-setup-python)
  83. (ein:ml-set-font-lock-defaults))
  84. (eval-after-load "auto-complete"
  85. '(add-to-list 'ac-modes 'ein:notebook-multilang-mode))
  86. ;;; Language setup functions
  87. (defun ein:ml-lang-setup-python ()
  88. (setq comment-start "# ")
  89. (setq comment-start-skip "#+\\s-*")
  90. (setq parse-sexp-lookup-properties t)
  91. (setq parse-sexp-ignore-comments t)
  92. (when (boundp 'python-mode-map)
  93. (set-keymap-parent ein:notebook-multilang-mode-map python-mode-map))
  94. (cond
  95. ((featurep 'python)
  96. (setq indent-line-function #'python-indent-line-function)
  97. (setq indent-region-function #'python-indent-region))
  98. ((featurep 'python-mode)
  99. ;; FIXME: write keymap setup for python-mode.el
  100. )))
  101. (defun ein:ml-lang-setup-markdown ()
  102. "Use `markdown-mode-map'. NOTE: This function is not used now."
  103. (when (featurep 'markdown-mode)
  104. (set-keymap-parent ein:notebook-multilang-mode-map markdown-mode-map)))
  105. ;; FIXME: dynamically call ein:ml-lang-setup-LANG using
  106. ;; `post-command-hook'.
  107. ;; FIMXE: add more ein:ml-lang-setup-LANG to switch kaymap.
  108. ;;; yasnippet
  109. (defvar ein:ml-yasnippet-parents '(python-mode markdown-mode)
  110. "Parent modes for `ein:notebook-multilang-mode' to register in yasnippet.")
  111. (defun ein:ml-setup-yasnippet ()
  112. (loop for define-parents in '(yas/define-parents
  113. yas--define-parents)
  114. when (fboundp define-parents)
  115. do (ignore-errors
  116. ;; `let' is for workaround the bug in yasnippet
  117. (let ((mode-sym 'ein:notebook-multilang-mode))
  118. (funcall define-parents
  119. mode-sym
  120. ein:ml-yasnippet-parents)))))
  121. (eval-after-load "yasnippet" '(ein:ml-setup-yasnippet))
  122. (provide 'ein-multilang)
  123. ;;; ein-multilang.el ends here