├── README.md ├── inferior-plisp.el └── plisp-mode.el /README.md: -------------------------------------------------------------------------------- 1 | # plisp-mode - Major mode for PicoLisp programming 2 | 3 | *Author:* Alexis (plisp-mode.el); Guillermo R. Palavecine , Thorsten Jolitz , Alexis (inferior-plisp.el)
4 | *URL:* [https://github.com/flexibeast/plisp-mode](https://github.com/flexibeast/plisp-mode)
5 | 6 | *This project is currently unmaintained, and needs a new 7 | maintainer. If you wish to take maintainership, please email 8 | Alexis.* 9 | 10 | `plisp-mode` provides a major mode for PicoLisp programming. 11 | 12 | The `plisp-mode` in this package has been built from scratch, and 13 | is not based on, nor connected with, the PicoLisp support for Emacs 14 | provided in [the PicoLisp 15 | distribution](http://software-lab.de/down.html), or the more 16 | recently [updated version of that 17 | support](https://github.com/tj64/picolisp-mode). At this stage, the 18 | main advantages provided by this package are: 19 | 20 | * access to the PicoLisp reference documentation, including via 21 | Eldoc; 22 | 23 | * basic Imenu support; 24 | 25 | * ease of customisability; and 26 | 27 | * a cleaner codebase. 28 | 29 | ## Table of Contents 30 | 31 | - [Features](#features) 32 | - [Installation](#installation) 33 | - [Usage](#usage) 34 | - [Syntax highlighting](#highlighting) 35 | - [REPL](#repl) 36 | - [Inferior PicoLisp](#inferior-picolisp) 37 | - [Org Babel](#org-babel) 38 | - [Documentation](#documentation) 39 | - [Commenting](#commenting) 40 | - [Indentation](#indentation) 41 | - [Miscellaneous](#miscellanous) 42 | - [TODO](#todo) 43 | - [Issues](#issues) 44 | - [License](#license) 45 | 46 | ## Features 47 | 48 | * Syntax highlighting of PicoLisp code. (But please read the below 49 | [note on syntax highlighting](#note-highlighting).) 50 | 51 | * Comint-based `pil` REPL buffers. 52 | 53 | * Quick access to documentation for symbol at point. 54 | 55 | ## Installation 56 | 57 | Install [plisp-mode from 58 | MELPA](http://melpa.org/#/plisp-mode), or put the 59 | `plisp-mode` folder in your load-path and do a `(require 60 | 'plisp-mode)`. 61 | 62 | ## Usage 63 | 64 | 65 | 66 | ### Syntax highlighting 67 | 68 | Enable syntax highlighting for a PicoLisp source buffer with M-x 69 | plisp-mode. 70 | 71 | ### REPL 72 | 73 | Start a `pil` REPL session with M-x plisp-repl or, from a 74 | `plisp-mode` buffer, with C-c C-i (`plisp-repl`). 75 | 76 | 77 | 78 | ### Inferior PicoLisp 79 | 80 | This package provides the `inferior-plisp` feature, a fork of the 81 | [`inferior-picolisp` library written by Guillermo Palavecino and 82 | Thorsten Jolitz](https://github.com/tj64/picolisp-mode/), modified 83 | to be compatible with `plisp-mode`. 84 | 85 | By default, `inferior-plisp` is loaded by `plisp-mode`; to disable 86 | this, set the variable `plisp-use-inferior-plisp` to `nil`. It can 87 | still be manually loaded with `(require 'inferior-plisp)`. 88 | 89 | With `inferior-plisp` loaded, the following bindings are available 90 | in `plisp-mode` and `plisp-repl-mode`: 91 | 92 | * M-C-x / C-c C-e : Send the current definition to the inferior PicoLisp 93 | process (`inferior-plisp-send-definition`). 94 | 95 | * C-x C-e : Send the last sexp before point to the inferior 96 | PicoLisp process (`inferior-plisp-send-last-sexp`). 97 | 98 | * C-c M-e : Send the current definition to the inferior PicoLisp 99 | process and switch to its buffer 100 | (`inferior-plisp-send-definition-and-go`). 101 | 102 | * C-c C-r : Send the region to the inferior PicoLisp process 103 | (`inferior-plisp-send-region`). 104 | 105 | * C-c M-r : Send the region to the inferior PicoLisp process and 106 | switch to its buffer (`inferior-plisp-send-region-and-go`). 107 | 108 | * C-c C-l : Load a PicoLisp file into the inferior PicoLisp 109 | process (`inferior-plisp-load-file`)." 110 | 111 | * C-c C-x : Switch to the inferior PicoLisp buffer 112 | (`inferior-plisp-switch-to-picolisp`). 113 | 114 | Multiple inferior PicoLisp processes can be created and used; the 115 | documentation for the variable `inferior-plisp-picolisp-buffer` 116 | provides more details. 117 | 118 | By default, `inferior-plisp` provides the feature 119 | `inferior-picolisp` required by `ob-picolisp`. To use another 120 | package to provide `inferior-picolisp`, set the 121 | `inferior-plisp-provide-inferior-picolisp` variable to `nil`. 122 | 123 | 124 | 125 | #### Org Babel 126 | 127 | By default, `plisp-mode` registers itself as providing the 128 | `picolisp-mode` needed to edit Org Babel PicoLisp source blocks 129 | with `org-edit-special`. If you wish to disable this, set the 130 | variable `plisp-provide-picolisp-mode` to `nil`. 131 | 132 | `inferior-plisp` can support Org Babel sessions: add 133 | `(inferior-plisp-support-ob-picolisp)` to your init file, and make 134 | sure the `org-babel-picolisp-cmd` variable defined by `ob-picolisp` 135 | is correctly specified for your system. 136 | 137 | ### Documentation 138 | 139 | Access documentation for the function at point with C-c C-d 140 | (`plisp-describe-symbol`). By default, documentation will be 141 | displayed via the `lynx` HTML browser. However, one can set the 142 | value of `plisp-documentation-method` to either a string 143 | containing the absolute path to an alternative browser, or - for 144 | users of Emacs 24.4 and above - to the symbol 145 | `plisp--shr-documentation`; this function uses the `shr` library 146 | to display the documentation in an Emacs buffer. The absolute path 147 | to the documentation is specified via 148 | `plisp-documentation-directory`, and defaults to 149 | `/usr/share/doc/picolisp/`. 150 | 151 | Eldoc support is available. 152 | 153 | If for some reason the PicoLisp documentation is not installed on 154 | the system, and cannot be installed, setting 155 | `plisp-documentation-unavailable` to `t` will prevent 156 | `plisp-mode` from trying to provide documentation. 157 | 158 | ### Commenting 159 | 160 | Comment a region in a `plisp-mode` buffer with C-c C-; 161 | (`plisp-comment-region`); uncomment a region in a 162 | `plisp-mode` buffer with C-c C-: 163 | (`plisp-uncomment-region`). By default one '#' character is 164 | added/removed; to specify more, supply a numeric prefix argument to 165 | either command. 166 | 167 | ### Indentation 168 | 169 | Indent a region in a `plisp-mode` buffer with C-c M-q 170 | (`plisp-indent-region`). Indentation is done via the `pilIndent` 171 | script provided with the current PicoLisp distribution; the path to 172 | the script is specified via the `plisp-pilindent-executable` 173 | variable. 174 | 175 | ### Miscellaneous 176 | 177 | SLIME users should read the below [note on SLIME](#note-slime). 178 | 179 | The various customisation options, including the faces used for 180 | syntax highlighting, are available via the `plisp` 181 | customize-group. 182 | 183 | 184 | 185 | ### A note on syntax highlighting 186 | 187 | PicoLisp's creator is opposed to syntax highlighting of symbols in 188 | PicoLisp, for [good 189 | reasons](http://www.mail-archive.com/picolisp@software-lab.de/msg05019.html). 190 | However, some - such as the author of this package! - feel that, 191 | even taking such issues into consideration, the benefits can 192 | outweigh the costs. (For example, when learning PicoLisp, it can be 193 | useful to get immediate visual feedback about unintentionally 194 | redefining a PicoLisp 'builtin'.) To accommodate both views, syntax 195 | highlighting can be enabled or disabled via the 196 | `plisp-syntax-highlighting-p` variable; by default, it is set to 197 | `t` (enabled). 198 | 199 | 200 | 201 | ### A note on [SLIME](https://github.com/slime/slime) 202 | 203 | The design of SLIME is such that it can override `plisp-mode` 204 | functionality. (The documentation for 205 | `plisp--disable-slime-modes` provides details.) The 206 | user-customisable variable `plisp-disable-slime-p` specifies 207 | whether to override these overrides, and defaults to `t`. 208 | 209 | ## TODO 210 | 211 | * Fix misalignment of single-'#' comments upon newline. 212 | 213 | 214 | 215 | ## Issues / bugs 216 | 217 | If you discover an issue or bug in `plisp-mode` not already 218 | noted: 219 | 220 | * as a TODO item, or 221 | 222 | * in [the project's "Issues" section on 223 | GitHub](https://github.com/flexibeast/plisp-mode/issues), 224 | 225 | please create a new issue with as much detail as possible, 226 | including: 227 | 228 | * which version of Emacs you're running on which operating system, 229 | and 230 | 231 | * how you installed `plisp-mode`. 232 | 233 | ## License 234 | 235 | [GNU General Public License version 236 | 3](http://www.gnu.org/licenses/gpl.html), or (at your option) any 237 | later version. 238 | 239 | 240 | --- 241 | Converted from `plisp-mode.el` by [*el2markdown*](https://github.com/Lindydancer/el2markdown). 242 | -------------------------------------------------------------------------------- /inferior-plisp.el: -------------------------------------------------------------------------------- 1 | ;;; inferior-plisp.el --- Run inferior PicoLisp processes 2 | 3 | ;; Copyright (C) 2009-2019 Guillermo R. Palavecine , Thorsten Jolitz , Alexis 4 | 5 | ;; Author: Guillermo R. Palavecine 6 | ;; Thorsten Jolitz 7 | ;; Alexis 8 | ;; Maintainer: Alexis 9 | ;; URL: https://github.com/flexibeast/picolisp-mode 10 | ;; Keywords: picolisp, lisp, programming, org 11 | 12 | ;; 13 | ;; This file is NOT part of GNU Emacs. 14 | ;; 15 | ;; This program is free software: you can redistribute it and/or 16 | ;; modify it under the terms of the GNU General Public License as 17 | ;; published by the Free Software Foundation, either version 3 of the 18 | ;; License, or (at your option) any later version. 19 | 20 | ;; This program is distributed in the hope that it will be useful, but 21 | ;; WITHOUT ANY WARRANTY; without even the implied warranty of 22 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 23 | ;; General Public License for more details. 24 | 25 | ;; You should have received a copy of the GNU General Public License 26 | ;; along with GNU Emacs. If not, see . 27 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 28 | ;; 29 | 30 | ;;; Commentary: 31 | 32 | ;; A fork of tj64's `inferior-picolisp' 33 | ;; (https://github.com/tj64/picolisp-mode/), modified to be compatible 34 | ;; with `plisp-mode' 35 | ;; (https://github.com/flexibeast/plisp-mode/). Initial work on the 36 | ;; fork was done by cryptorick (https://github.com/cryptorick). 37 | 38 | ;;; Code: 39 | 40 | 41 | (require 'comint) 42 | 43 | ;; 44 | ;; User-customisable settings. 45 | ;; 46 | 47 | (defgroup inferior-plisp nil 48 | "Run a PicoLisp process in a buffer." 49 | :group 'picolisp) 50 | 51 | (defcustom inferior-plisp-command-line "/usr/bin/pil +" 52 | "Command line for calling an inferior PicoLisp process." 53 | :type 'string 54 | :group 'inferior-plisp) 55 | 56 | (defcustom inferior-plisp-filter-regexp "\\`\\s *\\S ?\\S ?\\s *\\'" 57 | "Input matching this regexp are not saved on the history list. 58 | 59 | Defaults to a regexp ignoring all inputs of 0, 1, or 2 letters." 60 | :type 'regexp 61 | :group 'inferior-plisp) 62 | 63 | (defcustom inferior-plisp-load-hook nil 64 | "Hook run when `inferior-plisp' is loaded." 65 | :type 'hook 66 | :group 'inferior-plisp) 67 | 68 | (defcustom inferior-plisp-mode-hook nil 69 | "Hook for customizing `inferior-plisp'." 70 | :type 'hook 71 | :group 'inferior-plisp) 72 | 73 | (defcustom inferior-plisp-provide-inferior-picolisp t 74 | "Compatibility option for `ob-picolisp'. 75 | 76 | When set to `t', `inferior-plisp' will register itself as 77 | providing the `inferior-picolisp' feature required by 78 | `ob-picolisp', and will alias the `run-picolisp' function to the 79 | `inferior-plisp-run-picolisp' function. 80 | 81 | Set this to `nil' to if you wish to use another package to 82 | provide the `inferior-picolisp' feature." 83 | :type 'boolean 84 | :group 'inferior-plisp) 85 | 86 | (defcustom inferior-plisp-source-modes '(plisp-mode picolisp-mode) 87 | "List of modes which indicate a buffer contains PicoLisp source code. 88 | 89 | Used by `inferior-plisp-load-file' to determine defaults." 90 | :type '(repeat function) 91 | :group 'inferior-plisp ) 92 | 93 | (defvar inferior-plisp-picolisp-buffer nil 94 | "The current PicoLisp process buffer. 95 | 96 | MULTIPLE PROCESS SUPPORT 97 | ================================================================== 98 | 99 | `inferior-plisp' supports, in a fairly simple fashion, running 100 | multiple PicoLisp processes. To run multiple PicoLisp processes, 101 | you start the first up with \\[inferior-plisp-run-picolisp]. It 102 | will be in a buffer named *picolisp*. Rename this buffer with 103 | \\[rename-buffer]. You may now start up a new process with 104 | another \\[inferior-plisp-run-picolisp]. It will be in a new 105 | buffer, named *picolisp*. You can switch between the different 106 | process buffers with \\[switch-to-buffer]. 107 | 108 | Whenever \\[inferior-plisp-run-picolisp] starts a new process, it 109 | resets `inferior-plisp-picolisp-buffer' to be the new process' 110 | buffer. If you only run one process, this will do the right 111 | thing. If you run multiple processes, you can change 112 | `inferior-plisp-picolisp-buffer' to another process buffer with 113 | \\[set-variable].") 114 | 115 | 116 | ;; 117 | ;; Internal variables. 118 | ;; 119 | 120 | (defvar inferior-plisp--emacs-as-editor-p nil 121 | "If non-nil, use `eedit.l' instead of `edit.l'.") 122 | 123 | (defvar inferior-plisp--previous-load nil 124 | "Caches the last (directory . file) pair used by `inferior-plisp-load-file'. 125 | 126 | Used for determining the default in the next call to that function.") 127 | 128 | 129 | ;; 130 | ;; Internal functions. 131 | ;; 132 | 133 | (defun inferior-plisp--disable-line-editor () 134 | "Disable inbuilt PicoLisp line-editor. 135 | 136 | The line-editor is not needed when PicoLisp is run as an Emacs subprocess." 137 | (let ((pil-tmp-dir (expand-file-name "~/.pil/"))) 138 | ;; renaming of existing editor file 139 | (cond 140 | ;; abnormal condition, something went wrong before 141 | ((and 142 | (member "editor" (directory-files pil-tmp-dir)) 143 | (member "editor-orig" (directory-files pil-tmp-dir))) 144 | (let ((ed-size 145 | (nth 146 | 7 147 | (file-attributes 148 | (expand-file-name "editor" pil-tmp-dir)))) 149 | (ed-orig-size 150 | (nth 151 | 7 152 | (file-attributes 153 | (expand-file-name "editor-orig" pil-tmp-dir))))) 154 | (if (or (= ed-size 0) 155 | (<= ed-size ed-orig-size)) 156 | (delete-file 157 | (expand-file-name "editor" pil-tmp-dir)) 158 | (rename-file 159 | (expand-file-name "editor" pil-tmp-dir) 160 | (expand-file-name "editor-orig" pil-tmp-dir) 161 | 'OK-IF-ALREADY-EXISTS)))) 162 | ;; normal condition, only editor file exists 163 | ((member "editor" (directory-files pil-tmp-dir )) 164 | (rename-file 165 | (expand-file-name "editor" pil-tmp-dir) 166 | (expand-file-name "editor-orig" pil-tmp-dir)))) 167 | ;; after renaming, create new empty editor file 168 | (with-current-buffer 169 | (find-file-noselect 170 | (expand-file-name "editor" pil-tmp-dir)) 171 | (erase-buffer) 172 | (save-buffer) 173 | (kill-buffer)))) 174 | 175 | (defun inferior-plisp--get-editor-info () 176 | "Find out if Emacs is used as editor." 177 | (let* ((editor-file (expand-file-name "editor" "~/.pil/")) 178 | (editor-orig-file (expand-file-name "editor-orig" "~/.pil/")) 179 | (ed-file 180 | (cond 181 | ((file-exists-p editor-file) editor-file) 182 | ((file-exists-p editor-orig-file) editor-orig-file) 183 | (t nil)))) 184 | (when ed-file 185 | (with-current-buffer (find-file-noselect ed-file) 186 | (goto-char (point-min)) 187 | (if (re-search-forward "eedit" nil 'NOERROR) 188 | (setq inferior-plisp--emacs-as-editor-p t) 189 | (setq inferior-plisp--emacs-as-editor-p nil)) 190 | (kill-buffer))))) 191 | 192 | (defun inferior-plisp--get-old-input () 193 | "Snarf the sexp ending at point." 194 | (save-excursion 195 | (let ((end (point))) 196 | (backward-sexp) 197 | (buffer-substring (point) end)))) 198 | 199 | (defun inferior-plisp--input-filter (str) 200 | "Don't save anything matching `inferior-plisp-filter-regexp'." 201 | (not (string-match inferior-plisp-filter-regexp str)) ) 202 | 203 | (defun inferior-plisp--picolisp-process () 204 | "Return the current PicoLisp process, starting one if necessary. 205 | 206 | See variable `inferior-plisp-picolisp-buffer'." 207 | (unless (and inferior-plisp-picolisp-buffer 208 | (get-buffer inferior-plisp-picolisp-buffer) 209 | (comint-check-proc inferior-plisp-picolisp-buffer)) 210 | (inferior-plisp-interactively-start-process)) 211 | (or (get-buffer-process 212 | (if (eq major-mode 'inferior-plisp-mode) 213 | (current-buffer) 214 | inferior-plisp-picolisp-buffer)) 215 | (error "No current process. See `inferior-plisp-picolisp-buffer'"))) 216 | 217 | (defun inferior-plisp--reset-line-editor () 218 | "Reset inbuilt PicoLisp line-editor to original state." 219 | (let ((pil-tmp-dir (expand-file-name "~/.pil/"))) 220 | (if (member "editor-orig" (directory-files pil-tmp-dir)) 221 | (rename-file 222 | (expand-file-name "editor-orig" pil-tmp-dir) 223 | (expand-file-name "editor" pil-tmp-dir) 224 | 'OK-IF-ALREADY-EXISTS) 225 | (delete-file 226 | (expand-file-name "editor" pil-tmp-dir))))) 227 | 228 | 229 | ;; 230 | ;; User-facing functions. 231 | ;; 232 | 233 | (defun inferior-plisp-interactively-start-process (&optional cmd) 234 | "Start an inferior PicoLisp process. Return the process started. 235 | 236 | Since this command is run implicitly, always ask the user for the 237 | command to run." 238 | (save-window-excursion 239 | (inferior-plisp-run-picolisp 240 | (read-string "Run PicoLisp: " inferior-plisp-command-line)))) 241 | 242 | (defun inferior-plisp-load-file (file-name) 243 | "Load PicoLisp file FILE-NAME into the inferior PicoLisp process." 244 | (interactive 245 | (comint-get-source "Load PicoLisp file: " 246 | inferior-plisp--previous-load 247 | inferior-plisp-source-modes 248 | t)) ; `t' to indicate the file must already exist 249 | (comint-check-source file-name) 250 | (setq inferior-plisp--previous-load 251 | (cons (file-name-directory file-name) 252 | (file-name-nondirectory file-name))) 253 | (comint-send-string 254 | (inferior-plisp--picolisp-process) (concat "(load \"" file-name "\")\n"))) 255 | 256 | ;;;###autoload 257 | (defun inferior-plisp-run-picolisp (cmd) 258 | "Run an inferior PicoLisp process, input and output via buffer `*picolisp*'. 259 | 260 | If there is a process already running in `*picolisp*', switch to 261 | that buffer. 262 | 263 | With argument, allows you to edit the command line; default is value 264 | of `inferior-plisp-command-line'. 265 | 266 | Runs the hook `inferior-plisp-mode-hook' (after the `comint-mode-hook' 267 | is run)." 268 | 269 | (interactive (list 270 | (if current-prefix-arg 271 | (read-string "Run PicoLisp: " 272 | inferior-plisp-command-line) 273 | inferior-plisp-command-line))) 274 | (message "Using `run-picolisp' from `inferior-plisp'.") 275 | (when (not (comint-check-proc "*picolisp*")) 276 | (let ((cmdlist (split-string cmd))) 277 | (inferior-plisp--get-editor-info) 278 | (inferior-plisp--disable-line-editor) 279 | (set-buffer 280 | (apply 'make-comint 281 | "picolisp" 282 | (car cmdlist) 283 | nil 284 | ;; hack for multi-word PicoLisp arguments: 285 | ;; separate them with '_XXX_' in the 'cmd' arg 286 | ;; instead of blanks 287 | (mapcar 288 | (lambda (--arg) 289 | (replace-regexp-in-string 290 | "_XXX_" " " --arg)) 291 | (if inferior-plisp--emacs-as-editor-p 292 | (cons "@lib/eedit.l" (cdr cmdlist)) 293 | (cons "@lib/edit.l" (cdr cmdlist)))))) 294 | (inferior-plisp--reset-line-editor) 295 | (inferior-plisp-mode))) 296 | (setq inferior-plisp-command-line cmd) 297 | (setq inferior-plisp-picolisp-buffer "*picolisp*") 298 | (pop-to-buffer "*picolisp*")) 299 | 300 | (defun inferior-plisp-send-definition () 301 | "Send the current definition to the inferior PicoLisp process." 302 | (interactive) 303 | (save-excursion 304 | (end-of-defun) 305 | (let ((end (point))) 306 | (beginning-of-defun) 307 | (inferior-plisp-send-region 308 | (point) (progn (forward-sexp) (point)))))) 309 | 310 | (defun inferior-plisp-send-definition-and-go () 311 | "Send the current definition to the inferior PicoLisp, 312 | then switch to the process buffer." 313 | (interactive) 314 | (inferior-plisp-send-definition) 315 | (inferior-plisp-switch-to-picolisp t)) 316 | 317 | (defun inferior-plisp-send-last-sexp () 318 | "Send the previous sexp to the inferior PicoLisp process." 319 | (interactive) 320 | (inferior-plisp-send-region (save-excursion (backward-sexp) (point)) (point))) 321 | 322 | (defun inferior-plisp-send-region (start end) 323 | "Send the current region to the inferior PicoLisp process." 324 | (interactive "r") 325 | (let ((region-substring 326 | (replace-regexp-in-string "^\n" 327 | "" 328 | (buffer-substring start end)))) 329 | (progn 330 | (comint-send-string 331 | (inferior-plisp--picolisp-process) 332 | (if (string= "" (car (last (split-string region-substring "\n")))) 333 | region-substring 334 | (concat region-substring "\n")))))) 335 | 336 | (defun inferior-plisp-send-region-and-go (start end) 337 | "Send the current region to the inferior PicoLisp process, 338 | then switch to the process buffer." 339 | (interactive "r") 340 | (inferior-plisp-send-region start end) 341 | (inferior-plisp-switch-to-picolisp t)) 342 | 343 | 344 | ;;;###autoload 345 | (defun inferior-plisp-support-ob-picolisp () 346 | "Enable Org Babel session support. 347 | 348 | Needs `inferior-picolisp-provide-inferior-picolisp' set to `t'." 349 | (interactive) 350 | (if inferior-plisp-provide-inferior-picolisp 351 | (progn 352 | ;; We use `quote' here for Emacsmirror: 353 | ;; https://github.com/flexibeast/plisp-mode/pull/13 354 | (provide (quote inferior-picolisp)) 355 | (defalias 'run-picolisp 'inferior-plisp-run-picolisp)) 356 | (error "Unable to support ob-picolisp: please ensure 'inferior-plisp-provide-inferior-picolisp' is set to 't'"))) 357 | 358 | (defun inferior-plisp-switch-to-picolisp (eob-p) 359 | "Switch to the *picolisp* process buffer. 360 | 361 | With argument, position cursor at end of buffer." 362 | (interactive "P") 363 | (if (or (and inferior-plisp-picolisp-buffer 364 | (get-buffer inferior-plisp-picolisp-buffer)) 365 | (inferior-plisp-interactively-start-process) ) 366 | (pop-to-buffer inferior-plisp-picolisp-buffer) 367 | (error "No current process buffer. See `inferior-plisp-picolisp-buffer'") ) 368 | (when eob-p 369 | (push-mark) 370 | (goto-char (point-max)))) 371 | 372 | ;;;###autoload (add-hook 'same-window-buffer-names "*picolisp*") 373 | (define-derived-mode inferior-plisp-mode comint-mode "Inferior PicoLisp" 374 | "Major mode for interacting with an inferior PicoLisp process. 375 | 376 | A PicoLisp process can be started with 'M-x inferior-plisp-run-picolisp'. 377 | 378 | Customization: Entry to this mode runs the hooks on `comint-mode-hook' and 379 | `inferior-plisp-mode-hook' (in that order). 380 | 381 | For information on running multiple processes in multiple buffers, see 382 | documentation for the variable `inferior-plisp-picolisp-buffer'." 383 | ;; The following can be customised via `inferior-plisp-mode-hook'. 384 | (setq comint-prompt-regexp "^[^\n:?!]*[?!:]+ *") 385 | (setq comint-prompt-read-only nil) 386 | (setq comint-input-filter (function inferior-plisp--input-filter)) 387 | (setq comint-get-old-input (function inferior-plisp--get-old-input)) 388 | (setq mode-line-process '(":%s")) 389 | (setq comint-input-ring-file-name "~/.pil_history")) 390 | 391 | 392 | ;; -- 393 | 394 | (inferior-plisp-support-ob-picolisp) 395 | (run-hooks 'inferior-plisp-load-hook) 396 | (provide 'inferior-plisp) 397 | 398 | ;;; inferior-plisp.el ends here 399 | -------------------------------------------------------------------------------- /plisp-mode.el: -------------------------------------------------------------------------------- 1 | ;;; plisp-mode.el --- Major mode for PicoLisp programming. 2 | 3 | ;; Copyright (C) 2014-2019 Alexis 4 | 5 | ;; Author: Alexis (plisp-mode.el); Guillermo R. Palavecine , Thorsten Jolitz , Alexis (inferior-plisp.el) 6 | ;; Maintainer: Alexis 7 | ;; Created: 2014-11-18 8 | ;; URL: https://github.com/flexibeast/plisp-mode 9 | ;; Keywords: picolisp, lisp, programming 10 | 11 | ;; 12 | ;; This file is NOT part of GNU Emacs. 13 | ;; 14 | ;; This program is free software: you can redistribute it and/or 15 | ;; modify it under the terms of the GNU General Public License as 16 | ;; published by the Free Software Foundation, either version 3 of the 17 | ;; License, or (at your option) any later version. 18 | 19 | ;; This program is distributed in the hope that it will be useful, but 20 | ;; WITHOUT ANY WARRANTY; without even the implied warranty of 21 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 22 | ;; General Public License for more details. 23 | 24 | ;; You should have received a copy of the GNU General Public License 25 | ;; along with GNU Emacs. If not, see . 26 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 27 | ;; 28 | 29 | ;;; Commentary: 30 | 31 | ;; *This project is currently unmaintained, and needs a new 32 | ;; maintainer. If you wish to take maintainership, please email 33 | ;; Alexis.* 34 | 35 | ;; `plisp-mode' provides a major mode for PicoLisp programming. 36 | 37 | ;; The `plisp-mode' in this package has been built from scratch, and 38 | ;; is not based on, nor connected with, the PicoLisp support for Emacs 39 | ;; provided in [the PicoLisp 40 | ;; distribution](http://software-lab.de/down.html), or the more 41 | ;; recently [updated version of that 42 | ;; support](https://github.com/tj64/picolisp-mode). At this stage, the 43 | ;; main advantages provided by this package are: 44 | 45 | ;; * access to the PicoLisp reference documentation, including via 46 | ;; Eldoc; 47 | 48 | ;; * basic Imenu support; 49 | 50 | ;; * ease of customisability; and 51 | 52 | ;; * a cleaner codebase. 53 | 54 | ;; ## Table of Contents 55 | 56 | ;; - [Features](#features) 57 | ;; - [Installation](#installation) 58 | ;; - [Usage](#usage) 59 | ;; - [Syntax highlighting](#highlighting) 60 | ;; - [REPL](#repl) 61 | ;; - [Inferior PicoLisp](#inferior-picolisp) 62 | ;; - [Org Babel](#org-babel) 63 | ;; - [Documentation](#documentation) 64 | ;; - [Commenting](#commenting) 65 | ;; - [Indentation](#indentation) 66 | ;; - [Miscellaneous](#miscellanous) 67 | ;; - [TODO](#todo) 68 | ;; - [Issues](#issues) 69 | ;; - [License](#license) 70 | 71 | ;; ## Features 72 | 73 | ;; * Syntax highlighting of PicoLisp code. (But please read the below 74 | ;; [note on syntax highlighting](#note-highlighting).) 75 | 76 | ;; * Comint-based `pil' REPL buffers. 77 | 78 | ;; * Quick access to documentation for symbol at point. 79 | 80 | ;; ## Installation 81 | 82 | ;; Install [plisp-mode from 83 | ;; MELPA](http://melpa.org/#/plisp-mode), or put the 84 | ;; `plisp-mode' folder in your load-path and do a `(require 85 | ;; 'plisp-mode)'. 86 | 87 | ;; ## Usage 88 | 89 | ;; 90 | 91 | ;; ### Syntax highlighting 92 | 93 | ;; Enable syntax highlighting for a PicoLisp source buffer with `M-x 94 | ;; plisp-mode'. 95 | 96 | ;; ### REPL 97 | 98 | ;; Start a `pil' REPL session with `M-x plisp-repl' or, from a 99 | ;; `plisp-mode' buffer, with `C-c C-i' (`plisp-repl'). 100 | 101 | ;; 102 | 103 | ;; ### Inferior PicoLisp 104 | 105 | ;; This package provides the `inferior-plisp' feature, a fork of the 106 | ;; [`inferior-picolisp' library written by Guillermo Palavecino and 107 | ;; Thorsten Jolitz](https://github.com/tj64/picolisp-mode/), modified 108 | ;; to be compatible with `plisp-mode'. 109 | 110 | ;; By default, `inferior-plisp' is loaded by `plisp-mode'; to disable 111 | ;; this, set the variable `plisp-use-inferior-plisp' to `nil'. It can 112 | ;; still be manually loaded with `(require 'inferior-plisp)'. 113 | 114 | ;; With `inferior-plisp' loaded, the following bindings are available 115 | ;; in `plisp-mode' and `plisp-repl-mode': 116 | 117 | ;; * `M-C-x' / `C-c C-e' : Send the current definition to the inferior PicoLisp 118 | ;; process (`inferior-plisp-send-definition'). 119 | 120 | ;; * `C-x C-e' : Send the last sexp before point to the inferior 121 | ;; PicoLisp process (`inferior-plisp-send-last-sexp'). 122 | 123 | ;; * `C-c M-e' : Send the current definition to the inferior PicoLisp 124 | ;; process and switch to its buffer 125 | ;; (`inferior-plisp-send-definition-and-go'). 126 | 127 | ;; * `C-c C-r' : Send the region to the inferior PicoLisp process 128 | ;; (`inferior-plisp-send-region'). 129 | 130 | ;; * `C-c M-r' : Send the region to the inferior PicoLisp process and 131 | ;; switch to its buffer (`inferior-plisp-send-region-and-go'). 132 | 133 | ;; * `C-c C-l' : Load a PicoLisp file into the inferior PicoLisp 134 | ;; process (`inferior-plisp-load-file')." 135 | 136 | ;; * `C-c C-x' : Switch to the inferior PicoLisp buffer 137 | ;; (`inferior-plisp-switch-to-picolisp'). 138 | 139 | ;; Multiple inferior PicoLisp processes can be created and used; the 140 | ;; documentation for the variable `inferior-plisp-picolisp-buffer' 141 | ;; provides more details. 142 | 143 | ;; By default, `inferior-plisp' provides the feature 144 | ;; `inferior-picolisp' required by `ob-picolisp'. To use another 145 | ;; package to provide `inferior-picolisp', set the 146 | ;; `inferior-plisp-provide-inferior-picolisp' variable to `nil'. 147 | 148 | ;; 149 | 150 | ;; #### Org Babel 151 | 152 | ;; By default, `plisp-mode' registers itself as providing the 153 | ;; `picolisp-mode' needed to edit Org Babel PicoLisp source blocks 154 | ;; with `org-edit-special'. If you wish to disable this, set the 155 | ;; variable `plisp-provide-picolisp-mode' to `nil'. 156 | 157 | ;; `inferior-plisp' can support Org Babel sessions: add 158 | ;; `(inferior-plisp-support-ob-picolisp)' to your init file, and make 159 | ;; sure the `org-babel-picolisp-cmd' variable defined by `ob-picolisp' 160 | ;; is correctly specified for your system. 161 | 162 | ;; ### Documentation 163 | 164 | ;; Access documentation for the function at point with `C-c C-d' 165 | ;; (`plisp-describe-symbol'). By default, documentation will be 166 | ;; displayed via the `lynx' HTML browser. However, one can set the 167 | ;; value of `plisp-documentation-method' to either a string 168 | ;; containing the absolute path to an alternative browser, or - for 169 | ;; users of Emacs 24.4 and above - to the symbol 170 | ;; `plisp--shr-documentation'; this function uses the `shr' library 171 | ;; to display the documentation in an Emacs buffer. The absolute path 172 | ;; to the documentation is specified via 173 | ;; `plisp-documentation-directory', and defaults to 174 | ;; `/usr/share/doc/picolisp/'. 175 | 176 | ;; Eldoc support is available. 177 | 178 | ;; If for some reason the PicoLisp documentation is not installed on 179 | ;; the system, and cannot be installed, setting 180 | ;; `plisp-documentation-unavailable' to `t' will prevent 181 | ;; `plisp-mode' from trying to provide documentation. 182 | 183 | ;; ### Commenting 184 | 185 | ;; Comment a region in a `plisp-mode' buffer with `C-c C-;' 186 | ;; (`plisp-comment-region'); uncomment a region in a 187 | ;; `plisp-mode' buffer with `C-c C-:' 188 | ;; (`plisp-uncomment-region'). By default one '#' character is 189 | ;; added/removed; to specify more, supply a numeric prefix argument to 190 | ;; either command. 191 | 192 | ;; ### Indentation 193 | 194 | ;; Indent a region in a `plisp-mode' buffer with `C-c M-q' 195 | ;; (`plisp-indent-region'). Indentation is done via the `pilIndent' 196 | ;; script provided with the current PicoLisp distribution; the path to 197 | ;; the script is specified via the `plisp-pilindent-executable' 198 | ;; variable. 199 | 200 | ;; ### Miscellaneous 201 | 202 | ;; SLIME users should read the below [note on SLIME](#note-slime). 203 | 204 | ;; The various customisation options, including the faces used for 205 | ;; syntax highlighting, are available via the `plisp' 206 | ;; customize-group. 207 | 208 | ;; 209 | 210 | ;; ### A note on syntax highlighting 211 | 212 | ;; PicoLisp's creator is opposed to syntax highlighting of symbols in 213 | ;; PicoLisp, for [good 214 | ;; reasons](http://www.mail-archive.com/picolisp@software-lab.de/msg05019.html). 215 | ;; However, some - such as the author of this package! - feel that, 216 | ;; even taking such issues into consideration, the benefits can 217 | ;; outweigh the costs. (For example, when learning PicoLisp, it can be 218 | ;; useful to get immediate visual feedback about unintentionally 219 | ;; redefining a PicoLisp 'builtin'.) To accommodate both views, syntax 220 | ;; highlighting can be enabled or disabled via the 221 | ;; `plisp-syntax-highlighting-p' variable; by default, it is set to 222 | ;; `t' (enabled). 223 | 224 | ;; 225 | 226 | ;; ### A note on [SLIME](https://github.com/slime/slime) 227 | 228 | ;; The design of SLIME is such that it can override `plisp-mode' 229 | ;; functionality. (The documentation for 230 | ;; `plisp--disable-slime-modes' provides details.) The 231 | ;; user-customisable variable `plisp-disable-slime-p' specifies 232 | ;; whether to override these overrides, and defaults to `t'. 233 | 234 | ;; ## TODO 235 | 236 | ;; * Fix misalignment of single-'#' comments upon newline. 237 | 238 | ;; 239 | 240 | ;; ## Issues / bugs 241 | 242 | ;; If you discover an issue or bug in `plisp-mode' not already 243 | ;; noted: 244 | 245 | ;; * as a TODO item, or 246 | 247 | ;; * in [the project's "Issues" section on 248 | ;; GitHub](https://github.com/flexibeast/plisp-mode/issues), 249 | 250 | ;; please create a new issue with as much detail as possible, 251 | ;; including: 252 | 253 | ;; * which version of Emacs you're running on which operating system, 254 | ;; and 255 | 256 | ;; * how you installed `plisp-mode'. 257 | 258 | ;; ## License 259 | 260 | ;; [GNU General Public License version 261 | ;; 3](http://www.gnu.org/licenses/gpl.html), or (at your option) any 262 | ;; later version. 263 | 264 | ;;; Code: 265 | 266 | 267 | ;; 268 | ;; User-customisable settings. 269 | ;; 270 | 271 | (defgroup plisp nil 272 | "PicoLisp support." 273 | :group 'languages) 274 | 275 | (defcustom plisp-disable-slime-p t 276 | "Whether to disable SLIME modes in `plisp-mode' buffers." 277 | :type 'boolean 278 | :group 'plisp) 279 | 280 | (defcustom plisp-documentation-directory "/usr/share/doc/picolisp/" 281 | "Absolute path of the PicoLisp HTML documentation directory." 282 | :type 'directory 283 | :group 'plisp) 284 | 285 | (defcustom plisp-documentation-method 'plisp--shr-documentation 286 | "System to be used to display PicoLisp documentation." 287 | :type '(radio (function :tag "Function - must already be defined" 288 | :value 'plisp--shr-documentation) 289 | (file :tag "HTML browser - absolute path" 290 | :value "/usr/bin/lynx")) 291 | :group 'plisp) 292 | 293 | (defcustom plisp-documentation-unavailable nil 294 | "Whether the PicoLisp documentation is unavailable on the system. 295 | 296 | If for some reason the PicoLisp documentation is not installed on 297 | the system, and cannot be installed, setting this to `t' will prevent 298 | `plisp-mode' from trying to provide documentation." 299 | :type 'boolean 300 | :group 'plisp) 301 | 302 | (defcustom plisp-picolisp-executable "/usr/bin/picolisp" 303 | "Absolute path of the `picolisp' executable." 304 | :type '(file :must-match t) 305 | :group 'plisp) 306 | 307 | (defcustom plisp-pil-executable "/usr/bin/pil" 308 | "Absolute path of the `pil' executable." 309 | :type '(file :must-match t) 310 | :group 'plisp) 311 | 312 | (defcustom plisp-pilindent-executable "/usr/bin/pilIndent" 313 | "Absolute path of the `pilIndent' executable." 314 | :type '(file :must-match t) 315 | :group 'plisp) 316 | 317 | (defcustom plisp-provide-picolisp-mode t 318 | "Compatibility option for `ob-picolisp'. 319 | 320 | When set to `t', `plisp-mode' will register itself as providing 321 | the `picolisp-mode' feature required by `ob-picolisp' to edit 322 | PicoLisp source blocks via `org-edit-special'. 323 | 324 | Set this to `nil' to if you wish to use another package to 325 | provide the `picolisp-mode' feature to `ob-picolisp'." 326 | :type 'boolean 327 | :group 'plisp) 328 | 329 | (defcustom plisp-repl-debug-p t 330 | "Whether to enable debug mode in the REPL. 331 | Must be `t' to access documentation via `plisp-describe-symbol'." 332 | :type 'boolean 333 | :group 'plisp) 334 | 335 | (defcustom plisp-syntax-highlighting-p t 336 | "Whether to enable syntax highlighting." 337 | :type 'boolean 338 | :group 'plisp) 339 | 340 | (defcustom plisp-use-inferior-plisp t 341 | "Whether to enable `inferior-plisp' functionality." 342 | :type 'boolean 343 | :group 'plisp) 344 | 345 | (defgroup plisp-faces nil 346 | "Faces for PicoLisp syntax highlighting." 347 | :group 'plisp) 348 | 349 | (defface plisp-abstract-class-face 350 | '((t :inherit font-lock-type-face)) 351 | "Face for PicoLisp abstract classes." 352 | :group 'plisp-faces) 353 | 354 | (defface plisp-at-mark-face 355 | '((t :inherit font-lock-variable-name-face)) 356 | "Face for PicoLisp at-marks." 357 | :group 'plisp-faces) 358 | 359 | (defface plisp-builtin-face 360 | '((t :inherit font-lock-builtin-face)) 361 | "Face for PicoLisp builtins." 362 | :group 'plisp-faces) 363 | 364 | (defface plisp-comment-face 365 | '((t :inherit font-lock-comment-face)) 366 | "Face for PicoLisp comments." 367 | :group 'plisp-faces) 368 | 369 | (defface plisp-global-constant-face 370 | '((t :inherit font-lock-constant-face)) 371 | "Face for PicoLisp global constants." 372 | :group 'plisp-faces) 373 | 374 | (defface plisp-global-variable-face 375 | '((t :inherit font-lock-variable-name-face)) 376 | "Face for PicoLisp global variables." 377 | :group 'plisp-faces) 378 | 379 | (defface plisp-local-function-face 380 | '((t :inherit font-lock-function-name-face)) 381 | "Face for PicoLisp local functions." 382 | :group 'plisp-faces) 383 | 384 | (defface plisp-method-face 385 | '((t :inherit font-lock-function-name-face)) 386 | "Face for PicoLisp methods." 387 | :group 'plisp-faces) 388 | 389 | (defface plisp-normal-class-face 390 | '((t :inherit font-lock-type-face)) 391 | "Face for PicoLisp normal classes." 392 | :group 'plisp-faces) 393 | 394 | (defface plisp-transient-symbol-face 395 | '((t :inherit font-lock-string-face)) 396 | "Face for PicoLisp transient symbols." 397 | :group 'plisp-faces) 398 | 399 | 400 | ;; Initialise. 401 | ;; 402 | ;; 403 | 404 | (if plisp-use-inferior-plisp 405 | (require 'inferior-plisp)) 406 | 407 | 408 | ;; 409 | ;; Internal variables. 410 | ;; 411 | 412 | (defvar plisp-mode-map (make-sparse-keymap)) 413 | (define-key plisp-mode-map (kbd "C-c C-;") 'plisp-comment-region) 414 | (define-key plisp-mode-map (kbd "C-c C-:") 'plisp-uncomment-region) 415 | (define-key plisp-mode-map (kbd "C-c C-d") 'plisp-describe-symbol) 416 | (define-key plisp-mode-map (kbd "C-c C-i") 'plisp-repl) 417 | (define-key plisp-mode-map (kbd "C-c M-q") 'plisp-indent-region) 418 | (if plisp-use-inferior-plisp 419 | (progn 420 | (define-key plisp-mode-map (kbd "M-C-x") 'inferior-plisp-send-definition) 421 | (define-key plisp-mode-map (kbd "C-x C-e") 'inferior-plisp-send-last-sexp) 422 | (define-key plisp-mode-map (kbd "C-c C-e") 'inferior-plisp-send-definition) 423 | (define-key plisp-mode-map (kbd "C-c M-e") 'inferior-plisp-send-definition-and-go) 424 | (define-key plisp-mode-map (kbd "C-c C-r") 'inferior-plisp-send-region) 425 | (define-key plisp-mode-map (kbd "C-c M-r") 'inferior-plisp-send-region-and-go) 426 | (define-key plisp-mode-map (kbd "C-c C-l") 'inferior-plisp-load-file) 427 | (define-key plisp-mode-map (kbd "C-c C-x") 'inferior-plisp-switch-to-picolisp))) 428 | 429 | (defvar plisp-repl-mode-map (make-sparse-keymap)) 430 | (define-key plisp-repl-mode-map (kbd "C-c C-d") 'plisp-describe-symbol) 431 | (if plisp-use-inferior-plisp 432 | (progn 433 | (define-key plisp-repl-mode-map (kbd "M-C-x") 'inferior-plisp-send-definition) 434 | (define-key plisp-repl-mode-map (kbd "C-x C-e") 'inferior-plisp-send-last-sexp) 435 | (define-key plisp-mode-map (kbd "C-c C-e") 'inferior-plisp-send-definition) 436 | (define-key plisp-mode-map (kbd "C-c M-e") 'inferior-plisp-send-definition-and-go) 437 | (define-key plisp-mode-map (kbd "C-c C-r") 'inferior-plisp-send-region) 438 | (define-key plisp-mode-map (kbd "C-c M-r") 'inferior-plisp-send-region-and-go) 439 | (define-key plisp-mode-map (kbd "C-c C-l") 'inferior-plisp-load-file) 440 | (define-key plisp-mode-map (kbd "C-c C-x") 'inferior-plisp-switch-to-picolisp))) 441 | 442 | 443 | ;; http://software-lab.de/doc/ref.html#fun 444 | 445 | (defvar plisp-builtins 446 | '("!" "$" "$dat" "$tim" "%" "&" "*" "**" "*/" "*Allow" "*Bye" "*CPU" "*Class" "*Class" "*DB" "*Dbg" "*Dbg" "*Dbs" "*EAdr" "*Err" "*Fork" "*Hup" "*Led" "*Msg" "*OS" "*PPid" "*Pid" "*Prompt" "*Run" "*Scl" "*Sig1" "*Sig2" "*Solo" "*Tsm" "*Uni" "*Zap" "+" "+Alt" "+Any" "+Aux" "+Bag" "+Blob" "+Bool" "+Date" "+Dep" "+Entity" "+Fold" "+Hook" "+Hook2" "+Idx" "+IdxFold" "+Joint" "+Key" "+Link" "+List" "+Mis" "+Need" "+Number" "+Ref" "+Ref2" "+Sn" "+String" "+Swap" "+Symbol" "+Time" "+UB" "+index" "+relation" "-" "->" "/" ":" "::" ";" "<" "<=" "<>" "=" "=0" "=:" "==" "====" "=T" ">" ">=" ">>" "?" "@" "@@" "@@@" "This" "^" "abort" "abs" "accept" "accu" "acquire" "adr" "alarm" "align" "all" "allow" "allowed" "and" "any" "append" "append/3" "apply" "arg" "args" "argv" "as" "asoq" "assert" "asserta" "asserta/1" "assertz" "assertz/1" "assoc" "at" "atom" "aux" "balance" "be" "beep" "bench" "bin" "bind" "bit?" "blob" "blob!" "bool" "bool/3" "box" "box?" "by" "bye" "bytes" "caaaar" "caaadr" "caaar" "caadar" "caaddr" "caadr" "caar" "cache" "cadaar" "cadadr" "cadar" "caddar" "cadddr" "caddr" "cadr" "call" "call/1" "can" "car" "case" "casq" "catch" "cd" "cdaaar" "cdaadr" "cdaar" "cdadar" "cdaddr" "cdadr" "cdar" "cddaar" "cddadr" "cddar" "cdddar" "cddddr" "cdddr" "cddr" "cdr" "center" "chain" "char" "chdir" "chkTree" "chop" "circ" "circ?" "class" "clause" "clause/2" "clip" "close" "cmd" "cnt" "co" "collect" "commit" "con" "conc" "cond" "connect" "cons" "copy" "count" "ctl" "ctty" "curry" "cut" "d" "daemon" "dat$" "datStr" "datSym" "date" "day" "db" "db/3" "db/4" "db/5" "db:" "dbSync" "dbck" "dbs" "dbs+" "de" "debug" "dec" "def" "default" "del" "delete" "delete/3" "delq" "dep" "depth" "diff" "different/2" "dir" "dirname" "dm" "do" "doc" "e" "echo" "edit" "em" "env" "eof" "eol" "equal/2" "err" "errno" "eval" "expDat" "expTel" "expr" "ext?" "extend" "extern" "extra" "extract" "fail" "fail/0" "fetch" "fifo" "file" "fill" "filter" "fin" "finally" "find" "fish" "flg?" "flip" "flush" "fmt64" "fold" "fold/3" "for" "fork" "forked" "format" "free" "from" "full" "fully" "fun?" "gc" "ge0" "genKey" "get" "getd" "getl" "glue" "goal" "group" "gt0" "hash" "hax" "hd" "head" "head/3" "heap" "hear" "here" "hex" "host" "id" "idx" "if" "if2" "ifn" "import" "in" "inc" "inc!" "index" "info" "init" "insert" "intern" "ipid" "isa" "isa/2" "iter" "job" "journal" "key" "kids" "kill" "last" "later" "ld" "le0" "leaf" "length" "let" "let?" "lieu" "line" "lines" "link" "lint" "lintAll" "list" "listen" "lit" "load" "loc" "local" "locale" "lock" "loop" "low?" "lowc" "lst/3" "lst?" "lt0" "lup" "macro" "made" "mail" "make" "map" "map/3" "mapc" "mapcan" "mapcar" "mapcon" "maplist" "maps" "mark" "match" "max" "maxKey" "maxi" "member" "member/2" "memq" "meta" "meth" "method" "min" "minKey" "mini" "mix" "mmeq" "money" "more" "msg" "n0" "n==" "nT" "name" "nand" "native" "need" "new" "new!" "next" "nil" "nil/1" "nond" "nor" "not" "not/1" "nth" "num?" "obj" "object" "oct" "off" "offset" "on" "onOff" "once" "one" "open" "opid" "opt" "or" "or/2" "out" "pack" "pad" "pair" "part/3" "pass" "pat?" "patch" "path" "peek" "permute/2" "pick" "pico" "pilog" "pipe" "place" "poll" "pool" "pop" "port" "pp" "pr" "prEval" "pre?" "pretty" "prin" "prinl" "print" "println" "printsp" "prior" "proc" "prog" "prog1" "prog2" "prop" "protect" "prove" "prune" "push" "push1" "put" "put!" "putl" "pwd" "qsym" "query" "queue" "quit" "quote" "rand" "range" "range/3" "rank" "raw" "rc" "rd" "read" "recur" "recurse" "redef" "rel" "release" "remote/2" "remove" "repeat" "repeat/0" "replace" "request" "rest" "retract" "retract/1" "reverse" "rewind" "rollback" "root" "rot" "round" "rules" "run" "same/3" "scan" "scl" "script" "sect" "seed" "seek" "select" "select/3" "send" "seq" "set" "set!" "setq" "show" "show/1" "sigio" "size" "skip" "solve" "sort" "sp?" "space" "split" "sqrt" "stack" "stamp" "state" "stem" "step" "store" "str" "str?" "strDat" "strip" "sub?" "subr" "sum" "super" "sym" "sym?" "symbols" "sync" "sys" "t" "tab" "tail" "task" "telStr" "tell" "test" "text" "throw" "tick" "till" "tim$" "time" "timeout" "tmp" "tolr/3" "touch" "trace" "traceAll" "trail" "tree" "trim" "true/0" "try" "type" "u" "ubIter" "udp" "ultimo" "unbug" "undef" "unify" "uniq" "uniq/2" "unless" "until" "untrace" "up" "upd" "update" "upp?" "uppc" "use" "useKey" "usec" "val" "val/3" "var" "var:" "version" "vi" "view" "wait" "week" "what" "when" "while" "who" "wipe" "with" "wr" "wrap" "xchg" "xor" "x|" "yield" "yoke" "zap" "zapTree" "zero" "|")) 447 | 448 | (defvar plisp-builtins-by-length 449 | (let ((bs (copy-sequence plisp-builtins))) 450 | (sort bs #'(lambda (e1 e2) 451 | (> (length e1) (length e2))))) 452 | "List of PicoLisp builtins, sorted by length for use by 453 | `plisp-builtins-regex'.") 454 | 455 | (defvar plisp-builtins-regex 456 | (let ((s "") 457 | (firstp t)) 458 | (dolist (b plisp-builtins-by-length) 459 | (if (not firstp) 460 | (setq s (concat s "\\|" (regexp-quote b))) 461 | (progn 462 | (setq s (regexp-quote b)) 463 | (setq firstp nil)))) 464 | s) 465 | "Regex for use by `plisp-font-lock-keywords'.") 466 | 467 | ;; http://software-lab.de/doc/ref.html#conv 468 | 469 | (defvar plisp-font-lock-keywords 470 | `(("\\_<\\(T\\|NIL\\)\\_>" 471 | (1 'plisp-global-constant-face t)) 472 | ("\\(\\*[^]\\\"'(),[`~{}[:space:]]+\\)" 473 | (1 'plisp-global-variable-face t)) 474 | ("\\(\\+[a-z]\\S-*\\)" 475 | (1 'plisp-abstract-class-face t)) 476 | ("\\(\\+[A-Z][[:alpha:]]*\\)" 477 | (1 'plisp-normal-class-face t)) 478 | (,(concat "\\((\\|\\[\\)\\_<\\(" plisp-builtins-regex "\\)\\_>") 479 | (1 'default t) 480 | (2 'plisp-builtin-face t)) 481 | ("(\\(_\\S-+\\)" 482 | (1 'plisp-local-function-face t)) 483 | ("(\\([[:alpha:]]\\S-+>\\s-\\)" 484 | (1 'plisp-method-face t)) 485 | ("\\(\".+?\"\\)" 486 | (1 'plisp-transient-symbol-face t)) 487 | ("\\(@[0-9A-Z]?\\)" 488 | (1 'plisp-at-mark-face t)) 489 | ("^.*?\\(#+.*\\)$" 490 | (1 'plisp-comment-face t))) 491 | "Regexes for syntax-highlighting `plisp-mode' buffers.") 492 | 493 | ;; 494 | ;; http://software-lab.de/doc/ref.html#symbol: 495 | ;; 496 | ;; Internal symbol names can consist of any printable (non-whitespace) 497 | ;; character, except for the following meta characters: 498 | ;; 499 | ;; " ' ( ) , [ ] ` ~ { } 500 | ;; 501 | 502 | (defvar plisp-mode-syntax-table 503 | (let ((table (copy-syntax-table lisp-mode-syntax-table))) 504 | 505 | ;; " primarily indicates a transient symbol, even 506 | ;; though it can also be used to indicate strings. 507 | (modify-syntax-entry ?\" "_ " table) 508 | 509 | ;; Comment syntax. 510 | (modify-syntax-entry ?\# "< " table) 511 | 512 | ;; '[' and ']' can delimit sexps. 513 | (modify-syntax-entry ?\[ "(] " table) 514 | (modify-syntax-entry ?\] ")[ " table) 515 | 516 | table) 517 | 518 | "Syntax table used in `plisp-mode'.") 519 | 520 | 521 | ;; 522 | ;; Internal functions. 523 | ;; 524 | 525 | (defun plisp--create-plisp-mode-menu () 526 | "Internal function to create or recreate the plisp-mode menu." 527 | (easy-menu-define plisp-menu plisp-mode-map "Menu bar entry for `plisp-mode'" 528 | `("PicoLisp" 529 | ["Comment region" (plisp-comment-region) :keys "C-c C-;"] 530 | ["Uncomment region" (plisp-uncomment-region) :keys "C-c C-:"] 531 | ["Indent region" (plisp-indent-region) :keys "C-c M-q"] 532 | ,@(if plisp-use-inferior-plisp 533 | (list 534 | ["Send last sexp" (inferior-plisp-send-last-sexp) :keys "C-x C-e"] 535 | ["Send definition" (inferior-plisp-send-definition) :keys "M-C-x"] 536 | ["Send definition and go" (inferior-plisp-send-definition-and-go) :keys "C-c M-e"] 537 | ["Switch to *picolisp* buffer" (inferior-plisp-switch-to-picolisp) :keys "C-c C-x"])) 538 | ["PicoLisp REPL" (plisp-repl) :keys "C-c C-i"] 539 | ["Customize" (customize-group 'plisp) t]))) 540 | 541 | (defun plisp--disable-slime-modes () 542 | "Function to add to `lisp-mode-hook' if `plisp-disable-slime-p' 543 | is set to `t'. 544 | 545 | SLIME adds the function `slime-lisp-mode-hook' to the 546 | `lisp-mode-hook' variable. Since `plisp-mode' is defined as 547 | being derived from `lisp-mode', the effect of this is to enable 548 | various SLIME features in `plisp-mode' buffers, overriding 549 | `plisp-mode' functionality. 550 | 551 | This function thus overrides those overrides, and: 552 | 553 | * disables `slime-mode'; 554 | 555 | * disables `slime-autodoc-mode'; and 556 | 557 | * ensures that the value of `eldoc-documentation-function' is 558 | `plisp--eldoc-function'." 559 | (and (fboundp 'slime-mode) (slime-mode 0)) 560 | (and (fboundp 'slime-autodoc-mode) (slime-autodoc-mode 0)) 561 | (make-local-variable 'eldoc-documentation-function) 562 | (setq eldoc-documentation-function #'plisp--eldoc-function)) 563 | 564 | (defun plisp--eldoc-function () 565 | "Function for use by `eldoc-documentation-function'." 566 | (unless plisp-documentation-unavailable 567 | (let* ((sym (symbol-name (symbol-at-point))) 568 | (dl (plisp--extract-reference-documentation sym)) 569 | (result nil)) 570 | (if (string-or-null-p dl) 571 | (if (y-or-n-p "Documentation not found. (Check the value of `plisp-documentation-directory', or set `plisp-documentation-unavailable' to `t'.) Turn off Eldoc mode in this buffer? ") 572 | (eldoc-mode 0)) 573 | (unless (string= "nil" sym) 574 | (dotimes (i (/ (length dl) 2)) 575 | (let ((fst (nth (* i 2) dl)) 576 | (snd (nth (1+ (* i 2)) dl))) 577 | (if (eq 'dt (car-safe fst)) 578 | (cond 579 | ((eq 'cons (type-of (nth 2 fst))) 580 | (if (string= sym (cdaadr (nth 2 fst))) 581 | (setq result (concat (propertize sym 'face 'plisp-builtin-face) 582 | ", " 583 | (nth 2 (caddr (nth 2 fst))))))) 584 | ;; Handle the documentation for `c[ad]*[ad]r'. 585 | ((eq 'string (type-of (nth 2 fst))) 586 | (if (string= "cXr" (cdaadr (nth 59 fst))) 587 | (setq result (concat (propertize "c[ad]*ar" 'face 'plisp-builtin-face) 588 | ", " 589 | "(c[ad]*ar 'var) -> any" 590 | "; " 591 | (propertize "c[ad]*dr" 'face 'plisp-builtin-face) 592 | ", " 593 | "(c[ad]*dr 'lst) -> any")) 594 | ;; Ignore any other edge-cases in the documentation structure. 595 | (setq result nil))))))))) 596 | result))) 597 | 598 | (defun plisp--extract-reference-documentation (sym) 599 | "Helper function to extract the 'Function Reference' definition 600 | list from the PicoLisp documentation, where SYM is the symbol being 601 | looked up." 602 | (let* ((dl "Documentation not found. Please check the value of `plisp-documentation-directory'") 603 | (char (progn 604 | (string-match "^[[:punct:]]*\\([[:punct:]]\\|[[:alpha:]]\\)" sym) 605 | (upcase (match-string 1 sym)))) 606 | (doc (if (string-match "[[:alpha:]]" char) 607 | (concat plisp-documentation-directory "/ref" char ".html") 608 | (concat plisp-documentation-directory "/ref_.html")))) 609 | (if (file-readable-p doc) 610 | (let* ((bfr (generate-new-buffer " *PicoLisp documentation source*")) 611 | (dom (progn 612 | (switch-to-buffer bfr) 613 | (insert-file-contents doc) 614 | (libxml-parse-html-region (point-min) (point-max))))) 615 | (setq dl (nth 5 (nth 3 (nth 3 dom)))) 616 | (kill-buffer bfr))) 617 | dl)) 618 | 619 | (defun plisp--font-lock-syntactic-face-function (state) 620 | "No-op function to prevent font-lock from trying to fontify 621 | comments and strings. 622 | 623 | Since strings in PicoLisp are fundamentally (transient) 624 | symbols, they are marked as such in the PicoLisp syntax-table. 625 | However, this makes it complicated for Emacs to determine if 626 | a '#' character is a comment delimiter or merely a constituent 627 | of a string / transient symbol. So we override syntactic 628 | fontification with this no-op function, and fontify comments 629 | via `plisp-font-lock-keywords'." 630 | nil) 631 | 632 | (defun plisp--imenu-create-index () 633 | "Internal function to create an Imenu index." 634 | (let ((index '())) 635 | (setq index (append index (plisp--imenu-find-classes-and-members))) 636 | (setq index (append index (plisp--imenu-find-database-objects))) 637 | (setq index (append index (plisp--imenu-find-facts-and-rules))) 638 | (setq index (append index (plisp--imenu-find-functions))) 639 | (setq index (append index (plisp--imenu-find-global-variables))) 640 | index)) 641 | 642 | (defun plisp--imenu-find-classes-and-members () 643 | "Internal function to find PicoLisp classes and their 644 | associated methods and/or relations." 645 | (let ((classes '())) 646 | (goto-char (point-min)) 647 | (while (re-search-forward 648 | "^[[:space:]]*(class \\([+][[:alnum:]]+\\)" nil t) 649 | (let ((class (match-string 1)) 650 | (class-index (match-beginning 1)) 651 | (members '()) 652 | (methods '()) 653 | (relations '()) 654 | (next-class-index 0)) 655 | (setq members `(("Definition" . ,class-index))) 656 | (save-excursion 657 | (setq next-class-index 658 | (if (re-search-forward 659 | "^[[:space:]]*(class \\([+][[:alnum:]]+\\)" nil t) 660 | (match-beginning 1) 661 | (point-max)))) 662 | (save-excursion 663 | (while (re-search-forward "^[[:space:]]*(dm \\([[:alnum:]]+>\\)" 664 | next-class-index 665 | t) 666 | (setq methods 667 | (append methods 668 | `((,(match-string 1) . ,(match-beginning 1))))))) 669 | (setq methods `(("Methods" . ,methods))) 670 | (save-excursion 671 | (while (re-search-forward 672 | "^[[:space:]]*(rel \\([[:alnum:]]+\\)" next-class-index t) 673 | (setq relations 674 | (append relations 675 | `((,(match-string 1) . ,(match-beginning 1))))))) 676 | (setq relations `(("Relations" . ,relations))) 677 | (setq members (append members methods relations)) 678 | (setq classes (append classes `((,class . ,members)))))) 679 | (setq classes `(("Classes" . ,classes))) 680 | classes)) 681 | 682 | (defun plisp--imenu-find-database-objects () 683 | "Internal function to find PicoLisp database objects." 684 | (let ((re (concat "^[[:space:]]*(obj[[:space:]]+((\\([^)]+\\))[[:space:]]+" 685 | "\\(?:[^[:space:]]+[[:space:]]+\\)?\\([^[:space:]]+\\))")) 686 | (objs '())) 687 | (goto-char (point-min)) 688 | (while (re-search-forward re nil t) 689 | (let ((obj-class (match-string 1)) 690 | (obj-identifier (match-string 2)) 691 | (obj-position (match-beginning 2))) 692 | (if (assoc obj-class objs) 693 | (setcdr (assoc obj-class objs) 694 | (append (cdr (assoc obj-class objs)) 695 | `((,obj-identifier . ,obj-position)))) 696 | (setq objs 697 | (append objs 698 | `((,obj-class . ((,obj-identifier . ,obj-position))))))))) 699 | (setq objs `(("Database objects" . ,objs))) 700 | objs)) 701 | 702 | (defun plisp--imenu-find-facts-and-rules () 703 | "Internal function to find PicoLisp facts and/or rules." 704 | (plisp--imenu-find-things 705 | "Facts and rules" 706 | "^[[:space:]]*(be \\([[:alnum:]]+\\))")) 707 | 708 | (defun plisp--imenu-find-functions () 709 | "Internal function to find PicoLisp functions." 710 | (plisp--imenu-find-things 711 | "Functions" 712 | "^[[:space:]]*(de \\([^*][[:alnum:]*+_]+\\)[[:space:]]+(")) 713 | 714 | (defun plisp--imenu-find-global-variables () 715 | "Internal function to find PicoLisp global variables." 716 | (plisp--imenu-find-things 717 | "Global variables" 718 | "^[[:space:]]*(de \\([*][[:alnum:]*+]+\\)[[:space:]]+")) 719 | 720 | (defun plisp--imenu-find-things (name re) 721 | "Internal function to find PicoLisp components of type NAME 722 | that can be identified by a simple regular expression RE." 723 | (let ((things '())) 724 | (goto-char (point-min)) 725 | (while (re-search-forward re nil t) 726 | (setq things (append things 727 | `((,(match-string 1) . ,(match-beginning 1)))))) 728 | (setq things `((,name . ,things))) 729 | things)) 730 | 731 | (defun plisp--shr-documentation (sym) 732 | "Use `shr' to display documentation for symbol SYM at point." 733 | (unless plisp-documentation-unavailable 734 | (unless (or (> emacs-major-version 24) 735 | (and (= emacs-major-version 24) 736 | (> emacs-minor-version 3))) 737 | (error "Emacs 24.4 or greater required")) 738 | (let ((dl (plisp--extract-reference-documentation sym))) 739 | (if (string-or-null-p dl) 740 | (user-error dl)) 741 | (dotimes (i (/ (length dl) 2)) 742 | (let ((fst (nth (* i 2) dl)) 743 | (snd (nth (1+ (* i 2)) dl))) 744 | (if (eq 'dt (car-safe fst)) 745 | (cond 746 | ((eq 'cons (type-of (nth 2 fst))) 747 | (if (string= sym (cdaadr (nth 2 fst))) 748 | (progn 749 | (switch-to-buffer 750 | (generate-new-buffer 751 | (concat "*PicoLisp documentation - '" sym "' *"))) 752 | (insert 753 | (concat 754 | (propertize "Symbol:" 755 | 'face '(foreground-color . "ForestGreen")) 756 | " " 757 | (propertize sym 758 | 'face 'plisp-builtin-face) 759 | "\n\n")) 760 | (shr-insert-document snd) 761 | (goto-char (point-min)) 762 | (help-mode)))) 763 | ((eq 'string (type-of (nth 2 fst))) 764 | ;; Handle the documentation for `c[ad]*[ad]r'. 765 | (if (string= "cXr" (cdaadr (nth 59 fst))) 766 | (progn 767 | (switch-to-buffer 768 | (generate-new-buffer 769 | (concat "*PicoLisp documentation - 'cXr' *"))) 770 | (insert 771 | (concat 772 | (propertize "Symbol:" 773 | 'face '(foreground-color . "ForestGreen")) 774 | " " 775 | (propertize "c[ad]*[ad]r" 776 | 'face 'plisp-builtin-face) "\n\n")) 777 | (shr-insert-document snd) 778 | (goto-char (point-min)) 779 | (help-mode)) 780 | ;; Ignore any other edge-cases in the documentation structure. 781 | nil))))))))) 782 | 783 | 784 | ;; 785 | ;; User-facing functions. 786 | ;; 787 | 788 | (defun plisp-comment-region (&optional n) 789 | "Comment lines in region using N '#' characters. N can be 790 | specified by providing a numeric prefix argument; otherwise, 791 | N defaults to 1." 792 | (interactive "p") 793 | (if n 794 | (comment-region (region-beginning) (region-end) n) 795 | (comment-region (region-beginning) (region-end) 1))) 796 | 797 | (defun plisp-uncomment-region (&optional n) 798 | "Uncomment lines in region by removing N '#' characters. N can 799 | be specified by providing a numeric prefix argument; otherwise, 800 | N defaults to 1." 801 | (interactive "p") 802 | (if n 803 | (uncomment-region (region-beginning) (region-end) n) 804 | (comment-region (region-beginning) (region-end) 1))) 805 | 806 | (defun plisp-indent-region () 807 | "Indent the active region using the `pilIndent' script." 808 | (interactive) 809 | (unless (region-active-p) 810 | (user-error "Region is not active")) 811 | (let* ((beginning (region-beginning)) 812 | (end (region-end))) 813 | (shell-command-on-region 814 | beginning end 815 | plisp-pilindent-executable 816 | nil t))) 817 | 818 | (defun plisp-describe-symbol () 819 | "Display documentation for symbol at point, via method 820 | specified by `plisp-documentation-method'." 821 | (interactive) 822 | (unless plisp-documentation-unavailable 823 | (let ((process-environment 824 | (if (eq 'string (type-of plisp-documentation-method)) 825 | (add-to-list 'process-environment 826 | (concat "BROWSER=" plisp-documentation-method)) 827 | process-environment)) 828 | (sym (symbol-name 829 | (symbol-at-point)))) 830 | (if (member sym plisp-builtins) 831 | (cond 832 | ((eq 'symbol (type-of plisp-documentation-method)) 833 | (plisp--shr-documentation sym)) 834 | ((eq 'string (type-of plisp-documentation-method)) 835 | (start-process-shell-command 836 | "picolisp-doc" nil 837 | (concat "pil -\"doc (car (nth (argv) 3)\" -bye - '" sym "' +"))) 838 | (t 839 | (error "Unexpected value type in plisp-documentation-method"))) 840 | (message "No PicoLisp builtin at point."))))) 841 | 842 | ;;;###autoload 843 | (define-derived-mode plisp-mode lisp-mode "PicoLisp" 844 | "Major mode for PicoLisp programming. Derived from lisp-mode. 845 | 846 | \\{plisp-mode-map}" 847 | :group 'plisp 848 | :syntax-table plisp-mode-syntax-table 849 | 850 | (setq-local comment-start "#") 851 | (setq-local comment-start-skip "#+ *") 852 | (if plisp-syntax-highlighting-p 853 | (setq-local font-lock-defaults 854 | '(plisp-font-lock-keywords 855 | nil nil nil nil 856 | (font-lock-syntactic-face-function 857 | . plisp--font-lock-syntactic-face-function)))) 858 | (setq-local eldoc-documentation-function #'plisp--eldoc-function) 859 | (plisp--create-plisp-mode-menu) 860 | (setq-local imenu-create-index-function 'plisp--imenu-create-index) 861 | (setq-local imenu-sort-function 'imenu--sort-by-name) 862 | (imenu-add-menubar-index) 863 | (if plisp-disable-slime-p 864 | (progn 865 | (make-local-variable 'lisp-mode-hook) 866 | (add-hook 'lisp-mode-hook 'plisp--disable-slime-modes)))) 867 | 868 | ;;;###autoload 869 | (define-derived-mode plisp-repl-mode comint-mode "PicoLisp REPL" 870 | "Major mode for `pil' REPL sessions. Derived from comint-mode. 871 | 872 | \\{plisp-repl-mode-map}" 873 | :group 'plisp 874 | :syntax-table plisp-mode-syntax-table 875 | 876 | (setq-local comment-start "#") 877 | (setq-local comment-start-skip "#+ *") 878 | (if plisp-syntax-highlighting-p 879 | (setq-local font-lock-defaults 880 | '(plisp-font-lock-keywords 881 | nil nil nil nil 882 | (font-lock-syntactic-face-function 883 | . plisp--font-lock-syntactic-face-function)))) 884 | (setq-local eldoc-documentation-function #'plisp--eldoc-function)) 885 | 886 | ;;;###autoload 887 | (defun plisp-repl () 888 | "Start a `pil' session in a new `plisp-repl-mode' buffer." 889 | (interactive) 890 | (let ((process-environment 891 | (if (eq 'string (type-of plisp-documentation-method)) 892 | (add-to-list 'process-environment 893 | (concat "BROWSER=" plisp-documentation-method)) 894 | process-environment))) 895 | (make-comint "picolisp-repl" 896 | plisp-pil-executable nil (if plisp-repl-debug-p "+" nil)) 897 | (switch-to-buffer "*picolisp-repl*") 898 | (plisp-repl-mode))) 899 | 900 | ;;;###autoload 901 | (defun plisp-support-ob-picolisp () 902 | "Enable editing of Org Babel PicoLisp source blocks with `plisp-mode'. 903 | 904 | Needs `plisp-provide-picolisp-mode' set to `t'." 905 | (interactive) 906 | (if plisp-provide-picolisp-mode 907 | (progn 908 | (provide 'picolisp-mode) 909 | (defalias 'picolisp-mode 'plisp-mode)) 910 | (t (error "Unable to support ob-picolisp: please ensure 'plisp-provide-picolisp-mode' is set to 't'")))) 911 | 912 | 913 | ;; -- 914 | 915 | (plisp-support-ob-picolisp) 916 | (provide 'plisp-mode) 917 | 918 | ;;; plisp-mode.el ends here 919 | --------------------------------------------------------------------------------