| [6] | 1 | ;;; -*- Log: hemlock.log; Package: Hemlock -*-
|
|---|
| 2 | ;;;
|
|---|
| 3 | ;;; **********************************************************************
|
|---|
| 4 | ;;; This code was written as part of the CMU Common Lisp project at
|
|---|
| 5 | ;;; Carnegie Mellon University, and has been placed in the public domain.
|
|---|
| 6 | ;;;
|
|---|
| 7 | #+CMU (ext:file-comment
|
|---|
| 8 | "$Header$")
|
|---|
| 9 | ;;;
|
|---|
| 10 | ;;; **********************************************************************
|
|---|
| 11 | ;;;
|
|---|
| 12 | ;;; Written by Bill Chiles and Rob MacLachlan.
|
|---|
| 13 | ;;;
|
|---|
| 14 | ;;; Even more commands...
|
|---|
| 15 |
|
|---|
| 16 | (in-package :hemlock)
|
|---|
| 17 |
|
|---|
| 18 | (defhvar "Region Query Size"
|
|---|
| 19 | "A number-of-lines threshold that destructive, undoable region commands
|
|---|
| 20 | should ask the user about when the indicated region is too big."
|
|---|
| 21 | :value 30)
|
|---|
| 22 |
|
|---|
| 23 | (defun check-region-query-size (region)
|
|---|
| 24 | "Checks the number of lines in region against \"Region Query Size\" and
|
|---|
| 25 | asks the user if the region crosses this threshold. If the user responds
|
|---|
| 26 | negatively, then an editor error is signaled."
|
|---|
| 27 | (let ((threshold (or (value region-query-size) 0)))
|
|---|
| 28 | (if (and (plusp threshold)
|
|---|
| 29 | (>= (count-lines region) threshold)
|
|---|
| 30 | (not (prompt-for-y-or-n
|
|---|
| 31 | :prompt "Region size exceeds \"Region Query Size\". Confirm: "
|
|---|
| 32 | :must-exist t)))
|
|---|
| 33 | (editor-error))))
|
|---|
| 34 |
|
|---|
| [7007] | 35 | ;;; Do nothing, but do it well ...
|
|---|
| 36 | (defcommand "Do Nothing" (p)
|
|---|
| 37 | "Do nothing."
|
|---|
| 38 | "Absolutely nothing."
|
|---|
| 39 | (declare (ignore p)))
|
|---|
| [6] | 40 |
|
|---|
| 41 |
|
|---|
| [8428] | 42 | (defcommand "Abort Command" (p)
|
|---|
| 43 | "Abort reading a command in current view"
|
|---|
| 44 | "Aborts c-q, multi-key commands (e.g. c-x), prefix translation (e.g.
|
|---|
| 45 | ESC as Meta-), prefix arguments (e.g. c-u), ephemeral modes such as
|
|---|
| 46 | i-search, and prompted input (e.g. m-x)"
|
|---|
| 47 | (declare (ignore p))
|
|---|
| 48 | (abort-to-toplevel))
|
|---|
| 49 |
|
|---|
| [6] | 50 | ;;;; Casing commands...
|
|---|
| 51 |
|
|---|
| 52 | (defcommand "Uppercase Word" (p)
|
|---|
| 53 | "Uppercase a word at point.
|
|---|
| 54 | With prefix argument uppercase that many words."
|
|---|
| 55 | "Uppercase p words at the point."
|
|---|
| [11923] | 56 | (if (region-active-p)
|
|---|
| 57 | (hemlock::uppercase-region-command p)
|
|---|
| 58 | (filter-words p (current-point) #'string-upcase)))
|
|---|
| [6] | 59 |
|
|---|
| 60 | (defcommand "Lowercase Word" (p)
|
|---|
| 61 | "Uppercase a word at point.
|
|---|
| 62 | With prefix argument uppercase that many words."
|
|---|
| 63 | "Uppercase p words at the point."
|
|---|
| [11923] | 64 | (if (region-active-p)
|
|---|
| 65 | (hemlock::lowercase-region-command p)
|
|---|
| 66 | (filter-words p (current-point) #'string-downcase)))
|
|---|
| [6] | 67 |
|
|---|
| 68 | ;;; FILTER-WORDS implements "Uppercase Word" and "Lowercase Word".
|
|---|
| 69 | ;;;
|
|---|
| 70 | (defun filter-words (p point function)
|
|---|
| 71 | (let ((arg (or p 1)))
|
|---|
| 72 | (with-mark ((mark point))
|
|---|
| 73 | (if (word-offset (if (minusp arg) mark point) arg)
|
|---|
| 74 | (filter-region function (region mark point))
|
|---|
| 75 | (editor-error "Not enough words.")))))
|
|---|
| 76 |
|
|---|
| 77 | ;;; "Capitalize Word" is different than uppercasing and lowercasing because
|
|---|
| 78 | ;;; the differences between Hemlock's notion of what a word is and Common
|
|---|
| 79 | ;;; Lisp's notion are too annoying.
|
|---|
| 80 | ;;;
|
|---|
| 81 | (defcommand "Capitalize Word" (p)
|
|---|
| 82 | "Lowercase a word capitalizing the first character. With a prefix
|
|---|
| 83 | argument, capitalize that many words. A negative argument capitalizes
|
|---|
| 84 | words before the point, but leaves the point where it was."
|
|---|
| 85 | "Capitalize p words at the point."
|
|---|
| [11923] | 86 | (if (region-active-p)
|
|---|
| 87 | (hemlock::capitalize-region-command p)
|
|---|
| 88 | (let ((point (current-point))
|
|---|
| 89 | (arg (or p 1)))
|
|---|
| 90 | (with-mark ((start point)
|
|---|
| 91 | (end point))
|
|---|
| 92 | (when (minusp arg)
|
|---|
| 93 | (unless (word-offset start arg) (editor-error "No previous word.")))
|
|---|
| 94 | (do ((region (region start end))
|
|---|
| 95 | (cnt (abs arg) (1- cnt)))
|
|---|
| 96 | ((zerop cnt) (move-mark point end))
|
|---|
| 97 | (unless (find-not-attribute start :word-delimiter)
|
|---|
| 98 | (editor-error "No next word."))
|
|---|
| 99 | (move-mark end start)
|
|---|
| 100 | (unless (find-attribute end :word-delimiter)
|
|---|
| 101 | (buffer-end end))
|
|---|
| 102 | (capitalize-one-word region))))))
|
|---|
| [6] | 103 |
|
|---|
| [11923] | 104 | (defun capitalize-one-word (region)
|
|---|
| 105 | "Capitalize first word in region, moving region-start to region-end"
|
|---|
| 106 | (let* ((start (region-start region))
|
|---|
| 107 | (end (region-end region)))
|
|---|
| 108 | ;; (assert (mark<= start end))
|
|---|
| 109 | (loop
|
|---|
| 110 | (when (mark= start end)
|
|---|
| 111 | (return nil))
|
|---|
| 112 | (let ((ch (next-character start)))
|
|---|
| 113 | (when (alpha-char-p ch)
|
|---|
| 114 | (setf (next-character start) (char-upcase ch))
|
|---|
| 115 | (hi::buffer-note-modification (current-buffer) start 1)
|
|---|
| 116 | (mark-after start)
|
|---|
| 117 | (filter-region #'string-downcase region)
|
|---|
| 118 | (move-mark start end)
|
|---|
| 119 | (return t)))
|
|---|
| 120 | (mark-after start))))
|
|---|
| 121 |
|
|---|
| [6] | 122 | (defcommand "Uppercase Region" (p)
|
|---|
| 123 | "Uppercase words from point to mark."
|
|---|
| 124 | "Uppercase words from point to mark."
|
|---|
| 125 | (declare (ignore p))
|
|---|
| 126 | (twiddle-region (current-region) #'string-upcase "Uppercase Region"))
|
|---|
| 127 |
|
|---|
| 128 | (defcommand "Lowercase Region" (p)
|
|---|
| 129 | "Lowercase words from point to mark."
|
|---|
| 130 | "Lowercase words from point to mark."
|
|---|
| 131 | (declare (ignore p))
|
|---|
| 132 | (twiddle-region (current-region) #'string-downcase "Lowercase Region"))
|
|---|
| 133 |
|
|---|
| 134 | ;;; TWIDDLE-REGION implements "Uppercase Region" and "Lowercase Region".
|
|---|
| 135 | ;;;
|
|---|
| 136 | (defun twiddle-region (region function name)
|
|---|
| 137 | (let* (;; don't delete marks start and end since undo stuff will.
|
|---|
| 138 | (start (copy-mark (region-start region) :left-inserting))
|
|---|
| 139 | (end (copy-mark (region-end region) :left-inserting)))
|
|---|
| 140 | (let* ((region (region start end))
|
|---|
| 141 | (undo-region (copy-region region)))
|
|---|
| 142 | (filter-region function region)
|
|---|
| [11923] | 143 | (move-mark (current-point) end)
|
|---|
| [6] | 144 | (make-region-undo :twiddle name region undo-region))))
|
|---|
| 145 |
|
|---|
| [11923] | 146 | (defcommand "Capitalize Region" (p)
|
|---|
| 147 | "Capitalize words from point to mark."
|
|---|
| 148 | (declare (ignore p))
|
|---|
| 149 | (let* ((current-region (current-region))
|
|---|
| 150 | (start (copy-mark (region-start current-region) :left-inserting))
|
|---|
| 151 | (end (copy-mark (region-end current-region) :left-inserting))
|
|---|
| 152 | (region (region start end))
|
|---|
| 153 | (undo-region (copy-region region)))
|
|---|
| 154 | (capitalize-words-in-region region)
|
|---|
| 155 | (move-mark (current-point) end)
|
|---|
| 156 | (make-region-undo :twiddle "Capitalize Region" region undo-region)))
|
|---|
| [6] | 157 |
|
|---|
| [11923] | 158 | (defun capitalize-words-in-region (region)
|
|---|
| 159 | (let ((limit (region-end region)))
|
|---|
| 160 | (with-mark ((start (region-start region)))
|
|---|
| 161 | (with-mark ((end start))
|
|---|
| 162 | (let ((region (region start end)))
|
|---|
| 163 | (loop
|
|---|
| 164 | (unless (and (find-not-attribute start :word-delimiter)
|
|---|
| 165 | (mark< start limit))
|
|---|
| 166 | (return))
|
|---|
| 167 | ;; start is at a word constituent, there is at least one start < limit
|
|---|
| 168 | (move-mark end start)
|
|---|
| 169 | (unless (find-attribute end :word-delimiter)
|
|---|
| 170 | (buffer-end end))
|
|---|
| 171 | (when (mark< limit end)
|
|---|
| 172 | (move-mark end limit))
|
|---|
| 173 | (capitalize-one-word region)
|
|---|
| 174 | (move-mark start end)))))))
|
|---|
| 175 |
|
|---|
| 176 |
|
|---|
| [6] | 177 | ;;;; More stuff.
|
|---|
| 178 |
|
|---|
| 179 | (defcommand "Delete Previous Character Expanding Tabs" (p)
|
|---|
| 180 | "Delete the previous character.
|
|---|
| 181 | When deleting a tab pretend it is the equivalent number of spaces.
|
|---|
| 182 | With prefix argument, do it that many times."
|
|---|
| 183 | "Delete the P previous characters, expanding tabs into spaces."
|
|---|
| [6664] | 184 | (let* ((buffer (current-buffer))
|
|---|
| 185 | (region (hi::%buffer-current-region buffer)))
|
|---|
| 186 | (if region
|
|---|
| 187 | (delete-region region)
|
|---|
| 188 | (let ((point (current-point))
|
|---|
| 189 | (n (or p 1)))
|
|---|
| 190 | (when (minusp n)
|
|---|
| 191 | (editor-error "Delete Previous Character Expanding Tabs only accepts ~
|
|---|
| [6] | 192 | positive arguments."))
|
|---|
| [6664] | 193 | ;; Pre-calculate the number of characters that need to be deleted
|
|---|
| 194 | ;; and any remaining white space filling, allowing modification to
|
|---|
| 195 | ;; be avoided if there are not enough characters to delete.
|
|---|
| 196 | (let ((errorp nil)
|
|---|
| 197 | (del 0)
|
|---|
| 198 | (fill 0))
|
|---|
| 199 | (with-mark ((mark point))
|
|---|
| 200 | (dotimes (i n)
|
|---|
| 201 | (if (> fill 0)
|
|---|
| 202 | (decf fill)
|
|---|
| 203 | (let ((prev (previous-character mark)))
|
|---|
| 204 | (cond ((and prev (char= prev #\tab))
|
|---|
| 205 | (let ((pos (mark-column mark)))
|
|---|
| 206 | (mark-before mark)
|
|---|
| 207 | (incf fill (- pos (mark-column mark) 1)))
|
|---|
| 208 | (incf del))
|
|---|
| 209 | ((mark-before mark)
|
|---|
| 210 | (incf del))
|
|---|
| 211 | (t
|
|---|
| 212 | (setq errorp t)
|
|---|
| 213 | (return)))))))
|
|---|
| 214 | (cond ((and (not errorp) (kill-characters point (- del)))
|
|---|
| 215 | (with-mark ((mark point :left-inserting))
|
|---|
| 216 | (dotimes (i fill)
|
|---|
| 217 | (insert-character mark #\space))))
|
|---|
| 218 | (t
|
|---|
| 219 | (editor-error "There were not ~D characters before point." n))))))))
|
|---|
| [6] | 220 |
|
|---|
| 221 |
|
|---|
| 222 | (defvar *scope-table*
|
|---|
| 223 | (list (make-string-table :initial-contents
|
|---|
| 224 | '(("Global" . :global)
|
|---|
| 225 | ("Buffer" . :buffer)
|
|---|
| 226 | ("Mode" . :mode)))))
|
|---|
| 227 |
|
|---|
| 228 | (defun prompt-for-place (prompt help)
|
|---|
| 229 | (multiple-value-bind (word val)
|
|---|
| [8428] | 230 | (prompt-for-keyword :tables *scope-table*
|
|---|
| 231 | :prompt prompt
|
|---|
| [6] | 232 | :help help :default "Global")
|
|---|
| 233 | (declare (ignore word))
|
|---|
| 234 | (case val
|
|---|
| 235 | (:buffer
|
|---|
| 236 | (values :buffer (prompt-for-buffer :help "Buffer to be local to."
|
|---|
| 237 | :default (current-buffer))))
|
|---|
| 238 | (:mode
|
|---|
| 239 | (values :mode (prompt-for-keyword
|
|---|
| [8428] | 240 | :tables (list *mode-names*)
|
|---|
| [6] | 241 | :prompt "Mode: "
|
|---|
| 242 | :help "Mode to be local to."
|
|---|
| 243 | :default (buffer-major-mode (current-buffer)))))
|
|---|
| 244 | (:global :global))))
|
|---|
| 245 |
|
|---|
| 246 | (defcommand "Bind Key" (p)
|
|---|
| 247 | "Bind a command to a key.
|
|---|
| 248 | The command, key and place to make the binding are prompted for."
|
|---|
| 249 | "Prompt for stuff to do a bind-key."
|
|---|
| 250 | (declare (ignore p))
|
|---|
| 251 | (multiple-value-call #'bind-key
|
|---|
| 252 | (values (prompt-for-keyword
|
|---|
| [8428] | 253 | :tables (list *command-names*)
|
|---|
| [6] | 254 | :prompt "Command to bind: "
|
|---|
| 255 | :help "Name of command to bind to a key."))
|
|---|
| 256 | (values (prompt-for-key
|
|---|
| [8428] | 257 | :must-exist nil
|
|---|
| 258 | :prompt "Bind to: "
|
|---|
| [6] | 259 | :help "Key to bind command to, confirm to complete."))
|
|---|
| 260 | (prompt-for-place "Kind of binding: "
|
|---|
| [8428] | 261 | "The kind of binding to make.")))
|
|---|
| [6] | 262 |
|
|---|
| 263 | (defcommand "Delete Key Binding" (p)
|
|---|
| 264 | "Delete a key binding.
|
|---|
| 265 | The key and place to remove the binding are prompted for."
|
|---|
| 266 | "Prompt for stuff to do a delete-key-binding."
|
|---|
| 267 | (declare (ignore p))
|
|---|
| 268 | (let ((key (prompt-for-key
|
|---|
| [8428] | 269 | :must-exist nil
|
|---|
| 270 | :prompt "Delete binding: "
|
|---|
| [6] | 271 | :help "Key to delete binding from.")))
|
|---|
| 272 | (multiple-value-bind (kind where)
|
|---|
| 273 | (prompt-for-place "Kind of binding: "
|
|---|
| 274 | "The kind of binding to make.")
|
|---|
| 275 | (unless (get-command key kind where)
|
|---|
| 276 | (editor-error "No such binding: ~S" key))
|
|---|
| 277 | (delete-key-binding key kind where))))
|
|---|
| 278 |
|
|---|
| 279 |
|
|---|
| 280 | (defcommand "Set Variable" (p)
|
|---|
| 281 | "Prompt for a Hemlock variable and a new value."
|
|---|
| 282 | "Prompt for a Hemlock variable and a new value."
|
|---|
| 283 | (declare (ignore p))
|
|---|
| 284 | (multiple-value-bind (name var)
|
|---|
| 285 | (prompt-for-variable
|
|---|
| 286 | :prompt "Variable: "
|
|---|
| 287 | :help "The name of a variable to set.")
|
|---|
| 288 | (declare (ignore name))
|
|---|
| 289 | (setf (variable-value var)
|
|---|
| 290 | (handle-lisp-errors
|
|---|
| 291 | (eval (prompt-for-expression
|
|---|
| 292 | :prompt "Value: "
|
|---|
| 293 | :help "Expression to evaluate for new value."))))))
|
|---|
| 294 |
|
|---|
| 295 | (defcommand "Defhvar" (p)
|
|---|
| 296 | "Define a hemlock variable in some location. If the named variable exists
|
|---|
| 297 | currently, its documentation is propagated to the new instance, but this
|
|---|
| 298 | never prompts for documentation."
|
|---|
| 299 | "Define a hemlock variable in some location."
|
|---|
| 300 | (declare (ignore p))
|
|---|
| 301 | (let* ((name (nstring-capitalize (prompt-for-variable :must-exist nil)))
|
|---|
| 302 | (var (string-to-variable name))
|
|---|
| 303 | (doc (if (hemlock-bound-p var)
|
|---|
| 304 | (variable-documentation var)
|
|---|
| 305 | ""))
|
|---|
| 306 | (hooks (if (hemlock-bound-p var) (variable-hooks var)))
|
|---|
| 307 | (val (prompt-for-expression :prompt "Variable value: "
|
|---|
| 308 | :help "Value for the variable.")))
|
|---|
| 309 | (multiple-value-bind
|
|---|
| 310 | (kind where)
|
|---|
| 311 | (prompt-for-place
|
|---|
| 312 | "Kind of binding: "
|
|---|
| 313 | "Whether the variable is global, mode, or buffer specific.")
|
|---|
| 314 | (if (eq kind :global)
|
|---|
| 315 | (defhvar name doc :value val :hooks hooks)
|
|---|
| 316 | (defhvar name doc kind where :value val :hooks hooks)))))
|
|---|
| 317 |
|
|---|
| 318 |
|
|---|
| 319 | ;;; TRANSPOSE REGIONS uses CURRENT-REGION to signal an error if the current
|
|---|
| 320 | ;;; region is not active and to get start2 and end2 in proper order. Delete1,
|
|---|
| 321 | ;;; delete2, and delete3 are necessary since we are possibly ROTATEF'ing the
|
|---|
| 322 | ;;; locals end1/start1, start1/start2, and end1/end2, and we need to know which
|
|---|
| 323 | ;;; marks to dispose of at the end of all this stuff. When we actually get to
|
|---|
| 324 | ;;; swapping the regions, we must delete both up front if they both are to be
|
|---|
| 325 | ;;; deleted since we don't know what kind of marks are in start1, start2, end1,
|
|---|
| 326 | ;;; and end2, and the marks will be moving around unpredictably as we insert
|
|---|
| 327 | ;;; text at them. We copy point into ipoint for insertion purposes since one
|
|---|
| 328 | ;;; of our four marks is the point.
|
|---|
| 329 | ;;;
|
|---|
| 330 | (defcommand "Transpose Regions" (p)
|
|---|
| 331 | "Transpose two regions with endpoints defined by the mark stack and point.
|
|---|
| 332 | To use: mark start of region1, mark end of region1, mark start of region2,
|
|---|
| 333 | and place point at end of region2. Invoking this immediately following
|
|---|
| 334 | one use will put the regions back, but you will have to activate the
|
|---|
| 335 | current region."
|
|---|
| 336 | "Transpose two regions with endpoints defined by the mark stack and point."
|
|---|
| 337 | (declare (ignore p))
|
|---|
| 338 | (unless (>= (ring-length (value buffer-mark-ring)) 3)
|
|---|
| 339 | (editor-error "Need two marked regions to do Transpose Regions."))
|
|---|
| 340 | (let* ((region (current-region))
|
|---|
| 341 | (end2 (region-end region))
|
|---|
| 342 | (start2 (region-start region))
|
|---|
| 343 | (delete1 (pop-buffer-mark))
|
|---|
| 344 | (end1 (pop-buffer-mark))
|
|---|
| 345 | (delete2 end1)
|
|---|
| 346 | (start1 (pop-buffer-mark))
|
|---|
| 347 | (delete3 start1))
|
|---|
| 348 | ;;get marks in the right order, to simplify the code that follows
|
|---|
| 349 | (unless (mark<= start1 end1) (rotatef start1 end1))
|
|---|
| 350 | (unless (mark<= start1 start2)
|
|---|
| 351 | (rotatef start1 start2)
|
|---|
| 352 | (rotatef end1 end2))
|
|---|
| 353 | ;;order now guaranteed: <Buffer Start> start1 end1 start2 end2 <Buffer End>
|
|---|
| 354 | (unless (mark<= end1 start2)
|
|---|
| 355 | (editor-error "Can't transpose overlapping regions."))
|
|---|
| 356 | (let* ((adjacent-p (mark= end1 start2))
|
|---|
| 357 | (region1 (delete-and-save-region (region start1 end1)))
|
|---|
| 358 | (region2 (unless adjacent-p
|
|---|
| 359 | (delete-and-save-region (region start2 end2))))
|
|---|
| 360 | (point (current-point)))
|
|---|
| 361 | (with-mark ((ipoint point :left-inserting))
|
|---|
| [8428] | 362 | (let ((save-end2-loc (push-new-buffer-mark end2)))
|
|---|
| [6] | 363 | (ninsert-region (move-mark ipoint end2) region1)
|
|---|
| [8428] | 364 | (push-new-buffer-mark ipoint)
|
|---|
| [6] | 365 | (cond (adjacent-p
|
|---|
| [8428] | 366 | (push-new-buffer-mark start2)
|
|---|
| [6] | 367 | (move-mark point save-end2-loc))
|
|---|
| [8428] | 368 | (t (push-new-buffer-mark end1)
|
|---|
| [6] | 369 | (ninsert-region (move-mark ipoint end1) region2)
|
|---|
| 370 | (move-mark point ipoint))))))
|
|---|
| 371 | (delete-mark delete1)
|
|---|
| 372 | (delete-mark delete2)
|
|---|
| 373 | (delete-mark delete3)))
|
|---|
| 374 |
|
|---|
| 375 |
|
|---|
| 376 | (defcommand "Goto Absolute Line" (p)
|
|---|
| 377 | "Goes to the indicated line, if you counted them starting at the beginning
|
|---|
| 378 | of the buffer with the number one. If a prefix argument is supplied, that
|
|---|
| [6693] | 379 | is the line number; otherwise, the user is prompted."
|
|---|
| [6] | 380 | "Go to a user perceived line number."
|
|---|
| 381 | (let ((p (or p (prompt-for-expression
|
|---|
| 382 | :prompt "Line number: "
|
|---|
| 383 | :help "Enter an absolute line number to goto."))))
|
|---|
| 384 | (unless (and (integerp p) (plusp p))
|
|---|
| 385 | (editor-error "Must supply a positive integer."))
|
|---|
| 386 | (let ((point (current-point)))
|
|---|
| 387 | (with-mark ((m point))
|
|---|
| 388 | (unless (line-offset (buffer-start m) (1- p) 0)
|
|---|
| 389 | (editor-error "Not enough lines in buffer."))
|
|---|
| 390 | (move-mark point m)))))
|
|---|
| 391 |
|
|---|
| [6755] | 392 | (defcommand "Goto Absolute Position" (p)
|
|---|
| 393 | "Goes to the indicated character position, if you counted them
|
|---|
| 394 | starting at the beginning of the buffer with the number zero. If a
|
|---|
| 395 | prefix argument is supplied, that is the line number; otherwise, the
|
|---|
| 396 | user is prompted."
|
|---|
| 397 | "Go to a user perceived character position."
|
|---|
| 398 | (let ((p (or p (prompt-for-expression
|
|---|
| 399 | :prompt "Character Position: "
|
|---|
| 400 | :help "Enter an absolute character position to goto."))))
|
|---|
| 401 | (unless (and (integerp p) (not (minusp p)))
|
|---|
| 402 | (editor-error "Must supply a non-negatige integer."))
|
|---|
| 403 | (let ((point (current-point-unless-selection)))
|
|---|
| 404 | (when point
|
|---|
| [8428] | 405 | (unless (move-to-absolute-position point p)
|
|---|
| 406 | (buffer-end point))))))
|
|---|
| [6] | 407 |
|
|---|
| [6755] | 408 | (defcommand "What Cursor Position" (p)
|
|---|
| 409 | "Print info on current point position"
|
|---|
| 410 | "Print info on current point position"
|
|---|
| 411 | (declare (ignore p))
|
|---|
| 412 | (let* ((point (current-point))
|
|---|
| [8428] | 413 | (line-number (do* ((l 1 (1+ l))
|
|---|
| 414 | (mark-line (line-previous (mark-line point)) (line-previous mark-line)))
|
|---|
| 415 | ((null mark-line) l)))
|
|---|
| 416 | (charpos (mark-charpos point))
|
|---|
| 417 | (abspos (mark-absolute-position point))
|
|---|
| 418 | (char (next-character point))
|
|---|
| 419 | (size (count-characters (buffer-region (current-buffer)))))
|
|---|
| 420 | (message "Char: ~s point = ~d of ~d(~d%) line ~d column ~d"
|
|---|
| 421 | char abspos size (round (/ (* 100 abspos) size)) line-number charpos)))
|
|---|
| [6755] | 422 |
|
|---|
| [6] | 423 | (defcommand "Count Lines" (p)
|
|---|
| 424 | "Display number of lines in the region."
|
|---|
| 425 | "Display number of lines in the region."
|
|---|
| 426 | (declare (ignore p))
|
|---|
| 427 | (multiple-value-bind (region activep) (get-count-region)
|
|---|
| 428 | (message "~:[After point~;Active region~]: ~A lines"
|
|---|
| 429 | activep (count-lines region))))
|
|---|
| 430 |
|
|---|
| 431 | (defcommand "Count Words" (p)
|
|---|
| 432 | "Prints in the Echo Area the number of words in the region
|
|---|
| 433 | between the point and the mark by using word-offset. The
|
|---|
| 434 | argument is ignored."
|
|---|
| 435 | "Prints Number of Words in the Region"
|
|---|
| 436 | (declare (ignore p))
|
|---|
| 437 | (multiple-value-bind (region activep) (get-count-region)
|
|---|
| 438 | (let ((end-mark (region-end region)))
|
|---|
| 439 | (with-mark ((beg-mark (region-start region)))
|
|---|
| 440 | (let ((word-count 0))
|
|---|
| 441 | (loop
|
|---|
| 442 | (when (mark>= beg-mark end-mark)
|
|---|
| 443 | (return))
|
|---|
| 444 | (unless (word-offset beg-mark 1)
|
|---|
| 445 | (return))
|
|---|
| 446 | (incf word-count))
|
|---|
| 447 | (message "~:[After point~;Active region~]: ~D Word~:P"
|
|---|
| 448 | activep word-count))))))
|
|---|
| 449 |
|
|---|
| 450 | ;;; GET-COUNT-REGION -- Internal Interface.
|
|---|
| 451 | ;;;
|
|---|
| 452 | ;;; Returns the active region or the region between point and end-of-buffer.
|
|---|
| 453 | ;;; As a second value, it returns whether the region was active.
|
|---|
| 454 | ;;;
|
|---|
| 455 | ;;; Some searching commands use this routine.
|
|---|
| 456 | ;;;
|
|---|
| 457 | (defun get-count-region ()
|
|---|
| 458 | (if (region-active-p)
|
|---|
| 459 | (values (current-region) t)
|
|---|
| 460 | (values (region (current-point) (buffer-end-mark (current-buffer)))
|
|---|
| 461 | nil)))
|
|---|
| 462 |
|
|---|
| 463 |
|
|---|
| 464 | |
|---|
| 465 |
|
|---|
| 466 | ;;;; Some modes:
|
|---|
| 467 |
|
|---|
| 468 | (defcommand "Fundamental Mode" (p)
|
|---|
| 469 | "Put the current buffer into \"Fundamental\" mode."
|
|---|
| 470 | "Put the current buffer into \"Fundamental\" mode."
|
|---|
| 471 | (declare (ignore p))
|
|---|
| 472 | (setf (buffer-major-mode (current-buffer)) "Fundamental"))
|
|---|
| 473 |
|
|---|
| 474 | ;;;
|
|---|
| 475 | ;;; Text mode.
|
|---|
| 476 | ;;;
|
|---|
| 477 |
|
|---|
| 478 | (defmode "Text" :major-p t)
|
|---|
| 479 |
|
|---|
| 480 | (defcommand "Text Mode" (p)
|
|---|
| 481 | "Put the current buffer into \"Text\" mode."
|
|---|
| 482 | "Put the current buffer into \"Text\" mode."
|
|---|
| 483 | (declare (ignore p))
|
|---|
| 484 | (setf (buffer-major-mode (current-buffer)) "Text"))
|
|---|
| 485 |
|
|---|
| 486 | ;;;
|
|---|
| 487 | ;;; Caps-lock mode.
|
|---|
| 488 | ;;;
|
|---|
| 489 |
|
|---|
| 490 | (defmode "CAPS-LOCK")
|
|---|
| 491 |
|
|---|
| 492 | (defcommand "Caps Lock Mode" (p)
|
|---|
| 493 | "Simulate having a CAPS LOCK key. Toggle CAPS-LOCK mode. Zero or a
|
|---|
| 494 | negative argument turns it off, while a positive argument turns it
|
|---|
| 495 | on."
|
|---|
| 496 | "Simulate having a CAPS LOCK key. Toggle CAPS-LOCK mode. Zero or a
|
|---|
| 497 | negative argument turns it off, while a positive argument turns it
|
|---|
| 498 | on."
|
|---|
| 499 | (setf (buffer-minor-mode (current-buffer) "CAPS-LOCK")
|
|---|
| 500 | (if p
|
|---|
| 501 | (plusp p)
|
|---|
| 502 | (not (buffer-minor-mode (current-buffer) "CAPS-LOCK")))))
|
|---|
| 503 |
|
|---|
| 504 | (defcommand "Self Insert Caps Lock" (p)
|
|---|
| 505 | "Insert the last character typed, or the argument number of them.
|
|---|
| 506 | If the last character was an alphabetic character, then insert its
|
|---|
| 507 | capital form."
|
|---|
| 508 | "Insert the last character typed, or the argument number of them.
|
|---|
| 509 | If the last character was an alphabetic character, then insert its
|
|---|
| [8428] | 510 | capital form."
|
|---|
| [6] | 511 | (let ((char (char-upcase (last-char-typed))))
|
|---|
| 512 | (if (and p (> p 1))
|
|---|
| 513 | (insert-string (current-point) (make-string p :initial-element char))
|
|---|
| 514 | (insert-character (current-point) char))))
|
|---|