; -*- Mode:LISP; Package:STEVE; Readtable:CL; Base:10 -*- ;Tuesday the nineteenth of July, 1983; 10:50:58 pm ;Copyright (c) July 1983 by Christopher Eliot ; and Massachusetts Institute of Technology. ;Permission to copy all or part of this material is granted, provided ; that the copies are not made or distributed for resale, the MIT ; copyright notice and reference to the source file and the software ; distribution version appear, and that notice is given that copying ; is by permission of Massachusetts Institute of Technology. ; ;Comment manipulation functions. ; (defvar comment-start) (defvar comment-begin) (defvar comment-end) ;Null string means end of line. (defvar comment-column) (defvar comment-multi-line) (defun find-comment-in-line (line) (string-search-for-substring (line-chars line) comment-start 0 (line-char-count line))) (defun bp-to-comment (bp) (let ((column (find-comment-in-line (bp-line bp)))) (cond ((null column) nil) (t (send bp :set-pos column) t)))) (editor-bind-key #\meta-\; indent-for-comment) (editor-bind-key #\control-\; indent-for-comment) (defun indent-for-comment (&aux (bp *editor-cursor*) (line (bp-line bp))) (let ((column (find-comment-in-line line))) (cond ((null column) (send bp :set-pos (line-char-count (bp-line bp))) (delete-horizontal-space bp) (pad-to-column-with-tabs bp comment-column) (when (and (not (buffer-begin?)) (not (white-space? (send bp :peek-char-backward)))) (send bp :insert-char #\tab)) (send bp :insert-string comment-begin) (send bp :insert-string comment-end) (send bp :advance-pos (-& (string-length comment-end)))) ((and (=& (string-length comment-start) 1) (<& (1+& column) (line-char-count line)) (char= (char (line-chars line) (1+& column)) (char comment-start 0))) ;; Repeated comment. (cond ((and (<& (+& 2 column) (line-char-count line)) (char= (char (line-chars line) (+& 2 column)) (char comment-start 0))) (send bp :set-pos (+& 3 column))) (t (send bp :set-pos column) (send bp :backward-over-horizontal-white-space) (cond ((0p (bp-position bp)) ;Bp must be *editor-cursor* (funcall (internal-editor-lookup-key #\tab)) (send bp :advance-pos 2)) (t (send bp :set-pos (+& 2 column))))))) ((0p column) (send bp :set-pos (+& column (string-length comment-start)))) (t (send bp :set-pos column) (delete-horizontal-space bp) (pad-to-column-with-tabs bp comment-column) (when (and (not (buffer-begin?)) (not (white-space? (send bp :peek-char-backward)))) (send bp :insert-char #\tab)) (send bp :advance-pos (string-length comment-start)))) nil)) (defun pad-to-column-with-tabs (point column) (let ((hpos (edit-cursor-position-really point))) (cond ((>& hpos column) (send point :insert-char #\tab)) (t (let ((tabs (-& (/& column 8) (/& hpos 8)))) (loop repeat tabs do (send point :insert-char #\tab)) (loop repeat (if (+p tabs) (-& column (*& (/& column 8) 8)) (-& column hpos)) do (send point :insert-char #\space))))))) (editor-bind-key #\control-meta-\; kill-comment) (defun kill-comment () (when (bp-to-comment *editor-cursor*) (send *editor-cursor* :backward-over-horizontal-white-space) (kill-one-line-from-bp *editor-cursor*) (send *editor-cursor* :delete-chars-from-position)) nil) (editor-bind-key '(#\control-x #\;) set-comment-column) (defun set-comment-column () (setq comment-column (edit-cursor-position-really *editor-cursor*)) (with-notify-line-remaining (format terminal-io "Comment Column is ~a" comment-column)) nil) (defun null-comment-this-line () ;bar (and (bp-to-comment *editor-cursor*) ;foo (let ((line (bp-line *editor-cursor*)) (position (bp-position *editor-cursor*))) (or (and (=& (line-char-count line) (+& (string-length comment-begin) (string-length comment-end) position)) (send line :match-string comment-begin position) (send line :match-string comment-end (+& position (string-length comment-begin)))) (and (=& (line-char-count line) (+& (string-length comment-start) (string-length comment-end) position)) (send line :match-string comment-start position) (send line :match-string comment-end (+& position (string-length comment-start)))))))) (editor-bind-key #\meta-n down-comment-line) (defun down-comment-line () (when (null-comment-this-line) (kill-comment)) (when (null (line-next (bp-line *editor-cursor*))) (send (bp-line *editor-cursor*) :insert-line "")) (send *editor-cursor* :to-beginning-of-next-line) (indent-for-comment) nil) (editor-bind-key #\meta-p up-comment-line) (defun up-comment-line () (when (null-comment-this-line) (kill-comment)) (when (null (line-previous (bp-line *editor-cursor*))) (ed-warn :at-start)) (send *editor-cursor* :to-end-of-previous-line) (indent-for-comment) nil) (editor-bind-key #\meta-j indent-new-comment-line) (defun indent-new-comment-line () (cond ((0p comment-multi-line) (or (send (bp-line *editor-cursor*) :match-string comment-end (bp-position *editor-cursor*)) (send *editor-cursor* :insert-string comment-end)) (crlf) (indent-for-comment)) (t (linefeed))) nil) (editor-bind-key #\meta-linefeed indent-new-comment-line) (editor-bind-key #\control-meta-linefeed indent-new-comment-line) (editor-bind-key #\control-meta-j indent-new-comment-line) ;Add a prefix to every line in a region. (defun prefix-region-lines (prefix) (multiple-value-bind (bp1 bp2) (order-bps *editor-cursor* (get-mark)) (loop with limit-line = (line-next (bp-line bp2)) for line first (bp-line bp1) then (line-next line) until (or (null line) (eq line limit-line)) do (send line :insert-string 0 prefix)))) (defun unprefix-region-lines (prefix) (multiple-value-bind (bp1 bp2) (order-bps *editor-cursor* (get-mark)) (loop with limit-line = (line-next (bp-line bp2)) with length = (string-length prefix) for line first (bp-line bp1) then (line-next line) until (or (null line) (eq line limit-line)) if (send line :match-string prefix 0) do (send line :delete-characters 0 length)))) (bindmetax comment-region comment-region) (defun comment-region () (prefix-region-lines comment-start)) (bindmetax uncomment-region uncomment-region) (defun uncomment-region () (unprefix-region-lines comment-start)) ; ;Underlining and font changing. ; (editor-bind-key #\meta-# change-font-word) (defun change-font-word () (let ((bp (copy-bp *editor-cursor*))) (cond ((null (argument?)) ;;Move last font change 4forward one* word. (send bp :backward-to-char #\^F) (let ((change (send bp :get-char))) (send bp :advance-pos -1) (send bp :delete-characters 2) (send bp :forward-over-not-word) (send bp :forward-over-word) (send bp :insert-char #\control-f) (send bp :insert-char change))) ((+p *argument*) ;;Change font of last word. (send bp :backward-over-not-word) (send bp :backward-over-word) (send bp :insert-char #\control-f) (send bp :insert-char (%digit-weight-to-char *argument*)) (send bp :forward-over-word) (send bp :insert-string "*")) (t ;;Move last font change backward one word. (send bp :backward-to-char #\^F) (let ((change (send bp :get-char))) (send bp :advance-pos -1) (send bp :delete-characters 2) (send bp :backward-over-not-word) (send bp :backward-over-word) (cond ((char= (send bp :peek-char-backward) #\^F) (cond ((eq (char= (send bp :get-char) #\*) (char= change #\*)) (send (bp-line bp) :replace-char (bp-position bp) change)) (t (send bp :advance-pos -1) (send bp :delete-characters 2)))) (t (send bp :insert-char #\control-f) (send bp :insert-char change)))))) (send bp :send-if-handles :expire) nil)) ;Now is the time for all good men to come to the aid ;of their party. (editor-bind-key '(#\control-x #\#) change-font-region) (defun change-font-region () (multiple-value-bind (bp1 bp2) (order-bps *editor-cursor* (get-mark)) (cond ((eq (bp-line bp1) (bp-line bp2)) (delete-fonts-in-line (bp-line bp1) (bp-position bp1) (bp-position bp2))) (t (let ((line)) (delete-fonts-in-line (bp-line bp1) (bp-position bp1)) (setq line (bp-line bp2)) (delete-fonts-in-line line 0 (bp-position bp2)) (loop for nline first (line-next (bp-line bp1)) then (line-next nline) until (eq nline line) do (delete-fonts-in-line nline))))) (unless (-p *argument*) (send bp1 :insert-char #\^F) (send bp1 :insert-char (%digit-weight-to-char *argument*)) (send bp1 :advance-pos -2) ;so repeated use deletes this. (send bp2 :insert-string "*"))) nil) (defun delete-fonts-in-line (line &optional (p1 0) (p2 (line-char-count line))) (loop for offset upfrom 0 by 2 for pos = (%string-posq #\^F (line-chars line) p1 (-& p2 p1 offset)) while pos do (send line :delete-char pos) do (send line :delete-char pos)))