]> code.delx.au - gnu-emacs/blob - lisp/calc/calc-sel.el
(calc-display-raw): Fix docstring.
[gnu-emacs] / lisp / calc / calc-sel.el
1 ;;; calc-sel.el --- data selection functions for Calc
2
3 ;; Copyright (C) 1990, 1991, 1992, 1993, 2001 Free Software Foundation, Inc.
4
5 ;; Author: David Gillespie <daveg@synaptics.com>
6 ;; Maintainer: Jay Belanger <belanger@truman.edu>
7
8 ;; This file is part of GNU Emacs.
9
10 ;; GNU Emacs is distributed in the hope that it will be useful,
11 ;; but WITHOUT ANY WARRANTY. No author or distributor
12 ;; accepts responsibility to anyone for the consequences of using it
13 ;; or for whether it serves any particular purpose or works at all,
14 ;; unless he says so in writing. Refer to the GNU Emacs General Public
15 ;; License for full details.
16
17 ;; Everyone is granted permission to copy, modify and redistribute
18 ;; GNU Emacs, but only under the conditions described in the
19 ;; GNU Emacs General Public License. A copy of this license is
20 ;; supposed to have been given to you along with GNU Emacs so you
21 ;; can know your rights and responsibilities. It should be in a
22 ;; file named COPYING. Among other things, the copyright notice
23 ;; and this notice must be preserved on all copies.
24
25 ;;; Commentary:
26
27 ;;; Code:
28
29 ;; This file is autoloaded from calc-ext.el.
30
31 (require 'calc-ext)
32 (require 'calc-macs)
33
34 ;;; Selection commands.
35
36 (defvar calc-keep-selection t)
37
38 (defvar calc-selection-cache-entry nil)
39 (defvar calc-selection-cache-num)
40 (defvar calc-selection-cache-comp)
41 (defvar calc-selection-cache-offset)
42 (defvar calc-selection-true-num)
43
44 (defun calc-select-here (num &optional once keep)
45 (interactive "P")
46 (calc-wrapper
47 (calc-prepare-selection)
48 (let ((found (calc-find-selected-part))
49 (entry calc-selection-cache-entry))
50 (or (and keep (nth 2 entry))
51 (progn
52 (if once (progn
53 (setq calc-keep-selection nil)
54 (message "(Selection will apply to next command only)")))
55 (calc-change-current-selection
56 (if found
57 (if (and num (> (setq num (prefix-numeric-value num)) 0))
58 (progn
59 (while (and (>= (setq num (1- num)) 0)
60 (not (eq found (car entry))))
61 (setq found (calc-find-assoc-parent-formula
62 (car entry) found)))
63 found)
64 (calc-grow-assoc-formula (car entry) found))
65 (car entry))))))))
66
67 (defun calc-select-once (num)
68 (interactive "P")
69 (calc-select-here num t))
70
71 (defun calc-select-here-maybe (num)
72 (interactive "P")
73 (calc-select-here num nil t))
74
75 (defun calc-select-once-maybe (num)
76 (interactive "P")
77 (calc-select-here num t t))
78
79 (defun calc-select-additional ()
80 (interactive)
81 (calc-wrapper
82 (let (calc-keep-selection)
83 (calc-prepare-selection))
84 (let ((found (calc-find-selected-part))
85 (entry calc-selection-cache-entry))
86 (calc-change-current-selection
87 (if found
88 (let ((sel (nth 2 entry)))
89 (if sel
90 (progn
91 (while (not (or (eq sel (car entry))
92 (calc-find-sub-formula sel found)))
93 (setq sel (calc-find-assoc-parent-formula
94 (car entry) sel)))
95 sel)
96 (calc-grow-assoc-formula (car entry) found)))
97 (car entry))))))
98
99 (defun calc-select-more (num)
100 (interactive "P")
101 (calc-wrapper
102 (calc-prepare-selection)
103 (let ((entry calc-selection-cache-entry))
104 (if (nth 2 entry)
105 (let ((sel (nth 2 entry)))
106 (while (and (not (eq sel (car entry)))
107 (>= (setq num (1- (prefix-numeric-value num))) 0))
108 (setq sel (calc-find-assoc-parent-formula (car entry) sel)))
109 (calc-change-current-selection sel))
110 (calc-select-here num)))))
111
112 (defun calc-select-less (num)
113 (interactive "p")
114 (calc-wrapper
115 (calc-prepare-selection)
116 (let ((found (calc-find-selected-part))
117 (entry calc-selection-cache-entry))
118 (calc-change-current-selection
119 (and found
120 (let ((sel (nth 2 entry))
121 old index op)
122 (while (and sel
123 (not (eq sel found))
124 (>= (setq num (1- num)) 0))
125 (setq old sel
126 index (calc-find-sub-formula sel found))
127 (and (setq sel (and index (nth index old)))
128 calc-assoc-selections
129 (setq op (assq (car-safe sel) calc-assoc-ops))
130 (memq (car old) (nth index op))
131 (setq num (1+ num))))
132 sel))))))
133
134 (defun calc-select-part (num)
135 (interactive "P")
136 (or num (setq num (- last-command-char ?0)))
137 (calc-wrapper
138 (calc-prepare-selection)
139 (let ((sel (calc-find-nth-part (or (nth 2 calc-selection-cache-entry)
140 (car calc-selection-cache-entry))
141 num)))
142 (if sel
143 (calc-change-current-selection sel)
144 (error "%d is not a valid sub-formula index" num)))))
145
146 ;; The variables calc-fnp-op and calc-fnp-num are local to
147 ;; calc-find-nth-part (and calc-select-previous) but used by
148 ;; calc-find-nth-part-rec, which is called by them.
149 (defvar calc-fnp-op)
150 (defvar calc-fnp-num)
151
152 (defun calc-find-nth-part (expr calc-fnp-num)
153 (if (and calc-assoc-selections
154 (assq (car-safe expr) calc-assoc-ops))
155 (let (calc-fnp-op)
156 (calc-find-nth-part-rec expr))
157 (if (eq (car-safe expr) 'intv)
158 (and (>= calc-fnp-num 1) (<= calc-fnp-num 2) (nth (1+ calc-fnp-num) expr))
159 (and (not (Math-primp expr)) (>= calc-fnp-num 1) (< calc-fnp-num (length expr))
160 (nth calc-fnp-num expr)))))
161
162 (defun calc-find-nth-part-rec (expr) ; uses num, op
163 (or (if (and (setq calc-fnp-op (assq (car-safe (nth 1 expr)) calc-assoc-ops))
164 (memq (car expr) (nth 1 calc-fnp-op)))
165 (calc-find-nth-part-rec (nth 1 expr))
166 (and (= (setq calc-fnp-num (1- calc-fnp-num)) 0)
167 (nth 1 expr)))
168 (if (and (setq calc-fnp-op (assq (car-safe (nth 2 expr)) calc-assoc-ops))
169 (memq (car expr) (nth 2 calc-fnp-op)))
170 (calc-find-nth-part-rec (nth 2 expr))
171 (and (= (setq calc-fnp-num (1- calc-fnp-num)) 0)
172 (nth 2 expr)))))
173
174 (defun calc-select-next (num)
175 (interactive "p")
176 (if (< num 0)
177 (calc-select-previous (- num))
178 (calc-wrapper
179 (calc-prepare-selection)
180 (let* ((entry calc-selection-cache-entry)
181 (sel (nth 2 entry)))
182 (if sel
183 (progn
184 (while (>= (setq num (1- num)) 0)
185 (let* ((parent (calc-find-parent-formula (car entry) sel))
186 (p parent)
187 op)
188 (and (eq p t) (setq p nil))
189 (while (and (setq p (cdr p))
190 (not (eq (car p) sel))))
191 (if (cdr p)
192 (setq sel (or (and calc-assoc-selections
193 (setq op (assq (car-safe (nth 1 p))
194 calc-assoc-ops))
195 (memq (car parent) (nth 2 op))
196 (nth 1 (nth 1 p)))
197 (nth 1 p)))
198 (if (and calc-assoc-selections
199 (setq op (assq (car-safe parent) calc-assoc-ops))
200 (consp (setq p (calc-find-parent-formula
201 (car entry) parent)))
202 (eq (nth 1 p) parent)
203 (memq (car p) (nth 1 op)))
204 (setq sel (nth 2 p))
205 (error "No \"next\" sub-formula")))))
206 (calc-change-current-selection sel))
207 (if (Math-primp (car entry))
208 (calc-change-current-selection (car entry))
209 (calc-select-part num)))))))
210
211 (defun calc-select-previous (num)
212 (interactive "p")
213 (if (< num 0)
214 (calc-select-next (- num))
215 (calc-wrapper
216 (calc-prepare-selection)
217 (let* ((entry calc-selection-cache-entry)
218 (sel (nth 2 entry)))
219 (if sel
220 (progn
221 (while (>= (setq num (1- num)) 0)
222 (let* ((parent (calc-find-parent-formula (car entry) sel))
223 (p (cdr-safe parent))
224 (prev nil)
225 op)
226 (if (eq (car-safe parent) 'intv) (setq p (cdr p)))
227 (while (and (not (eq (car p) sel))
228 (setq prev (car p)
229 p (cdr p))))
230 (if prev
231 (setq sel (or (and calc-assoc-selections
232 (setq op (assq (car-safe prev)
233 calc-assoc-ops))
234 (memq (car parent) (nth 1 op))
235 (nth 2 prev))
236 prev))
237 (if (and calc-assoc-selections
238 (setq op (assq (car-safe parent) calc-assoc-ops))
239 (consp (setq p (calc-find-parent-formula
240 (car entry) parent)))
241 (eq (nth 2 p) parent)
242 (memq (car p) (nth 2 op)))
243 (setq sel (nth 1 p))
244 (error "No \"previous\" sub-formula")))))
245 (calc-change-current-selection sel))
246 (if (Math-primp (car entry))
247 (calc-change-current-selection (car entry))
248 (let ((len (if (and calc-assoc-selections
249 (assq (car (car entry)) calc-assoc-ops))
250 (let (calc-fnp-op (calc-fnp-num 0))
251 (calc-find-nth-part-rec (car entry))
252 (- 1 calc-fnp-num))
253 (length (car entry)))))
254 (calc-select-part (- len num)))))))))
255
256 (defun calc-find-parent-formula (expr part)
257 (cond ((eq expr part) t)
258 ((Math-primp expr) nil)
259 (t
260 (let ((p expr) res)
261 (while (and (setq p (cdr p))
262 (not (setq res (calc-find-parent-formula
263 (car p) part)))))
264 (and p
265 (if (eq res t) expr res))))))
266
267
268 (defun calc-find-assoc-parent-formula (expr part)
269 (calc-grow-assoc-formula expr (calc-find-parent-formula expr part)))
270
271 (defun calc-grow-assoc-formula (expr part)
272 (if calc-assoc-selections
273 (let ((op (assq (car-safe part) calc-assoc-ops)))
274 (if op
275 (let (new)
276 (while (and (consp (setq new (calc-find-parent-formula
277 expr part)))
278 (memq (car new)
279 (nth (calc-find-sub-formula new part) op)))
280 (setq part new))))
281 part)
282 part))
283
284 (defun calc-find-sub-formula (expr part)
285 (cond ((eq expr part) t)
286 ((Math-primp expr) nil)
287 (t
288 (let ((num 1))
289 (while (and (setq expr (cdr expr))
290 (not (calc-find-sub-formula (car expr) part)))
291 (setq num (1+ num)))
292 (and expr num)))))
293
294 (defun calc-unselect (num)
295 (interactive "P")
296 (calc-wrapper
297 (calc-prepare-selection num)
298 (calc-change-current-selection nil)))
299
300 (defun calc-clear-selections ()
301 (interactive)
302 (calc-wrapper
303 (let ((limit (calc-stack-size))
304 (n 1))
305 (while (<= n limit)
306 (if (calc-top n 'sel)
307 (progn
308 (calc-prepare-selection n)
309 (calc-change-current-selection nil)))
310 (setq n (1+ n))))
311 (calc-clear-command-flag 'position-point)))
312
313 (defun calc-show-selections (arg)
314 (interactive "P")
315 (calc-wrapper
316 (calc-preserve-point)
317 (setq calc-show-selections (if arg
318 (> (prefix-numeric-value arg) 0)
319 (not calc-show-selections)))
320 (let ((p calc-stack))
321 (while (and p
322 (or (null (nth 2 (car p)))
323 (equal (car p) calc-selection-cache-entry)))
324 (setq p (cdr p)))
325 (or (and p
326 (let ((calc-selection-cache-default-entry
327 calc-selection-cache-entry))
328 (calc-do-refresh)))
329 (and calc-selection-cache-entry
330 (let ((sel (nth 2 calc-selection-cache-entry)))
331 (setcar (nthcdr 2 calc-selection-cache-entry) nil)
332 (calc-change-current-selection sel)))))
333 (message (if calc-show-selections
334 "Displaying only selected part of formulas"
335 "Displaying all but selected part of formulas"))))
336
337 ;; The variables calc-final-point-line and calc-final-point-column
338 ;; are declared in calc.el, and are used throughout.
339 (defvar calc-final-point-line)
340 (defvar calc-final-point-column)
341
342 (defun calc-preserve-point ()
343 (or (looking-at "\\.\n+\\'")
344 (progn
345 (setq calc-final-point-line (+ (count-lines (point-min) (point))
346 (if (bolp) 1 0))
347 calc-final-point-column (current-column))
348 (calc-set-command-flag 'position-point))))
349
350 (defun calc-enable-selections (arg)
351 (interactive "P")
352 (calc-wrapper
353 (calc-preserve-point)
354 (setq calc-use-selections (if arg
355 (> (prefix-numeric-value arg) 0)
356 (not calc-use-selections)))
357 (calc-set-command-flag 'renum-stack)
358 (message (if calc-use-selections
359 "Commands operate only on selected sub-formulas"
360 "Selections of sub-formulas have no effect"))))
361
362 (defun calc-break-selections (arg)
363 (interactive "P")
364 (calc-wrapper
365 (calc-preserve-point)
366 (setq calc-assoc-selections (if arg
367 (<= (prefix-numeric-value arg) 0)
368 (not calc-assoc-selections)))
369 (message (if calc-assoc-selections
370 "Selection treats a+b+c as a sum of three terms"
371 "Selection treats a+b+c as (a+b)+c"))))
372
373 (defun calc-prepare-selection (&optional num)
374 (or num (setq num (calc-locate-cursor-element (point))))
375 (setq calc-selection-true-num num
376 calc-keep-selection t)
377 (or (> num 0) (setq num 1))
378 ;; (if (or (< num 1) (> num (calc-stack-size)))
379 ;; (error "Cursor must be positioned on a stack element"))
380 (let* ((entry (calc-top num 'entry))
381 ww w)
382 (or (equal entry calc-selection-cache-entry)
383 (progn
384 (setcar entry (calc-encase-atoms (car entry)))
385 (setq calc-selection-cache-entry entry
386 calc-selection-cache-num num
387 calc-selection-cache-comp
388 (let ((math-comp-tagged t))
389 (math-compose-expr (car entry) 0))
390 calc-selection-cache-offset
391 (+ (car (math-stack-value-offset calc-selection-cache-comp))
392 (length calc-left-label)
393 (if calc-line-numbering 4 0))))))
394 (calc-preserve-point))
395
396 ;;; The following ensures that no two subformulas will be "eq" to each other!
397 (defun calc-encase-atoms (x)
398 (if (or (not (consp x))
399 (equal x '(float 0 0)))
400 (list 'cplx x 0)
401 (calc-encase-atoms-rec x)
402 x))
403
404 (defun calc-encase-atoms-rec (x)
405 (or (Math-primp x)
406 (progn
407 (if (eq (car x) 'intv)
408 (setq x (cdr x)))
409 (while (setq x (cdr x))
410 (if (or (not (consp (car x)))
411 (equal (car x) '(float 0 0)))
412 (setcar x (list 'cplx (car x) 0))
413 (calc-encase-atoms-rec (car x)))))))
414
415 ;; The variable math-comp-sel-tag is local to calc-find-selected-part,
416 ;; but is used by math-comp-sel-flat-term and math-comp-add-string-sel
417 ;; in calccomp.el, which are called (indirectly) by calc-find-selected-part.
418
419 (defun calc-find-selected-part ()
420 (let* ((math-comp-sel-hpos (- (current-column) calc-selection-cache-offset))
421 toppt
422 (lcount 0)
423 (spaces 0)
424 (math-comp-sel-vpos (save-excursion
425 (beginning-of-line)
426 (let ((line (point)))
427 (calc-cursor-stack-index
428 calc-selection-cache-num)
429 (setq toppt (point))
430 (while (< (point) line)
431 (forward-line 1)
432 (setq spaces (+ spaces
433 (current-indentation))
434 lcount (1+ lcount)))
435 (- lcount (math-comp-ascent
436 calc-selection-cache-comp) -1))))
437 (math-comp-sel-cpos (- (point) toppt calc-selection-cache-offset
438 spaces lcount))
439 (math-comp-sel-tag nil))
440 (and (>= math-comp-sel-hpos 0)
441 (> calc-selection-true-num 0)
442 (math-composition-to-string calc-selection-cache-comp 1000000))
443 (nth 1 math-comp-sel-tag)))
444
445 (defun calc-change-current-selection (sub-expr)
446 (or (eq sub-expr (nth 2 calc-selection-cache-entry))
447 (let ((calc-prepared-composition calc-selection-cache-comp)
448 (buffer-read-only nil)
449 top)
450 (calc-set-command-flag 'renum-stack)
451 (setcar (nthcdr 2 calc-selection-cache-entry) sub-expr)
452 (calc-cursor-stack-index calc-selection-cache-num)
453 (setq top (point))
454 (calc-cursor-stack-index (1- calc-selection-cache-num))
455 (delete-region top (point))
456 (let ((calc-selection-cache-default-entry calc-selection-cache-entry))
457 (insert (math-format-stack-value calc-selection-cache-entry)
458 "\n")))))
459
460 (defun calc-top-selected (&optional n m)
461 (and calc-any-selections
462 calc-use-selections
463 (progn
464 (or n (setq n 1))
465 (or m (setq m 1))
466 (calc-check-stack (+ n m -1))
467 (let ((top (nthcdr (+ m calc-stack-top -1) calc-stack))
468 (sel nil))
469 (while (>= (setq n (1- n)) 0)
470 (if (nth 2 (car top))
471 (setq sel (if sel t (nth 2 (car top)))))
472 (setq top (cdr top)))
473 sel))))
474
475 ;; The variables calc-rsf-old and calc-rsf-new are local to
476 ;; calc-replace-sub-formula, but used by calc-replace-sub-formula-rec,
477 ;; which is called by calc-replace-sub-formula.
478 (defvar calc-rsf-old)
479 (defvar calc-rsf-new)
480
481 (defun calc-replace-sub-formula (expr calc-rsf-old calc-rsf-new)
482 (setq calc-rsf-new (calc-encase-atoms calc-rsf-new))
483 (calc-replace-sub-formula-rec expr))
484
485 (defun calc-replace-sub-formula-rec (expr)
486 (cond ((eq expr calc-rsf-old) calc-rsf-new)
487 ((Math-primp expr) expr)
488 (t
489 (cons (car expr)
490 (mapcar 'calc-replace-sub-formula-rec (cdr expr))))))
491
492 (defun calc-sel-error ()
493 (error "Illegal operation on sub-formulas"))
494
495 (defun calc-replace-selections (n vals m)
496 (if (calc-top-selected n m)
497 (let ((num (length vals)))
498 (calc-preserve-point)
499 (cond
500 ((= n num)
501 (let* ((old (calc-top-list n m 'entry))
502 (new nil)
503 (sel nil)
504 val)
505 (while old
506 (if (nth 2 (car old))
507 (setq val (calc-encase-atoms (car vals))
508 new (cons (calc-replace-sub-formula (car (car old))
509 (nth 2 (car old))
510 val)
511 new)
512 sel (cons val sel))
513 (setq new (cons (car vals) new)
514 sel (cons nil sel)))
515 (setq vals (cdr vals)
516 old (cdr old)))
517 (calc-pop-stack n m t)
518 (calc-push-list (nreverse new)
519 m (and calc-keep-selection (nreverse sel)))))
520 ((= num 1)
521 (let* ((old (calc-top-list n m 'entry))
522 more)
523 (while (and old (not (nth 2 (car old))))
524 (setq old (cdr old)))
525 (setq more old)
526 (while (and (setq more (cdr more)) (not (nth 2 (car more)))))
527 (and more
528 (calc-sel-error))
529 (calc-pop-stack n m t)
530 (if old
531 (let ((val (calc-encase-atoms (car vals))))
532 (calc-push-list (list (calc-replace-sub-formula
533 (car (car old))
534 (nth 2 (car old))
535 val))
536 m (and calc-keep-selection (list val))))
537 (calc-push-list vals))))
538 (t (calc-sel-error))))
539 (calc-pop-stack n m t)
540 (calc-push-list vals m)))
541
542 (defun calc-delete-selection (n)
543 (let ((entry (calc-top n 'entry)))
544 (if (nth 2 entry)
545 (if (eq (nth 2 entry) (car entry))
546 (progn
547 (calc-pop-stack 1 n t)
548 (calc-push-list '(0) n))
549 (let ((parent (calc-find-parent-formula (car entry) (nth 2 entry)))
550 (repl nil))
551 (calc-preserve-point)
552 (calc-pop-stack 1 n t)
553 (cond ((or (memq (car parent) '(* / %))
554 (and (eq (car parent) '^)
555 (eq (nth 2 parent) (nth 2 entry))))
556 (setq repl 1))
557 ((memq (car parent) '(vec calcFunc-min calcFunc-max)))
558 ((and (assq (car parent) calc-tweak-eqn-table)
559 (= (length parent) 3))
560 (setq repl 'del))
561 (t
562 (setq repl 0)))
563 (cond
564 ((eq repl 'del)
565 (calc-push-list (list
566 (calc-normalize
567 (calc-replace-sub-formula
568 (car entry)
569 parent
570 (if (eq (nth 2 entry) (nth 1 parent))
571 (nth 2 parent)
572 (nth 1 parent)))))
573 n))
574 (repl
575 (calc-push-list (list
576 (calc-normalize
577 (calc-replace-sub-formula (car entry)
578 (nth 2 entry)
579 repl)))
580 n))
581 (t
582 (calc-push-list (list
583 (calc-normalize
584 (calc-replace-sub-formula (car entry)
585 parent
586 (delq (nth 2 entry)
587 (copy-sequence
588 parent)))))
589 n)))))
590 (calc-pop-stack 1 n t))))
591
592 (defun calc-roll-down-with-selections (n m)
593 (let ((vals (append (calc-top-list m 1)
594 (calc-top-list (- n m) (1+ m))))
595 (sels (append (calc-top-list m 1 'sel)
596 (calc-top-list (- n m) (1+ m) 'sel))))
597 (calc-pop-push-list n vals 1 sels)))
598
599 (defun calc-roll-up-with-selections (n m)
600 (let ((vals (append (calc-top-list (- n m) 1)
601 (calc-top-list m (- n m -1))))
602 (sels (append (calc-top-list (- n m) 1 'sel)
603 (calc-top-list m (- n m -1) 'sel))))
604 (calc-pop-push-list n vals 1 sels)))
605
606 ;; The variable calc-sel-reselect is local to several functions
607 ;; which call calc-auto-selection.
608 (defvar calc-sel-reselect)
609
610 (defun calc-auto-selection (entry)
611 (or (nth 2 entry)
612 (progn
613 (setq calc-sel-reselect nil)
614 (calc-prepare-selection)
615 (calc-grow-assoc-formula (car entry) (calc-find-selected-part)))))
616
617 (defun calc-copy-selection ()
618 (interactive)
619 (calc-wrapper
620 (calc-preserve-point)
621 (let* ((num (max 1 (calc-locate-cursor-element (point))))
622 (entry (calc-top num 'entry)))
623 (calc-push (or (calc-auto-selection entry) (car entry))))))
624
625 (defun calc-del-selection ()
626 (interactive)
627 (calc-wrapper
628 (calc-preserve-point)
629 (let* ((num (max 1 (calc-locate-cursor-element (point))))
630 (entry (calc-top num 'entry))
631 (sel (calc-auto-selection entry)))
632 (setcar (nthcdr 2 entry) (and (not (eq sel (car entry))) sel))
633 (calc-delete-selection num))))
634
635 (defun calc-enter-selection ()
636 (interactive)
637 (calc-wrapper
638 (calc-preserve-point)
639 (let* ((num (max 1 (calc-locate-cursor-element (point))))
640 (calc-sel-reselect calc-keep-selection)
641 (entry (calc-top num 'entry))
642 (expr (car entry))
643 (sel (or (calc-auto-selection entry) expr))
644 alg)
645 (let ((calc-dollar-values (list sel))
646 (calc-dollar-used 0))
647 (setq alg (calc-do-alg-entry "" "Replace selection with: "))
648 (and alg
649 (progn
650 (setq alg (calc-encase-atoms (car alg)))
651 (calc-pop-push-record-list 1 "repl"
652 (list (calc-replace-sub-formula
653 expr sel alg))
654 num
655 (list (and calc-sel-reselect alg))))))
656 (calc-handle-whys))))
657
658 (defun calc-edit-selection ()
659 (interactive)
660 (calc-wrapper
661 (calc-preserve-point)
662 (let* ((num (max 1 (calc-locate-cursor-element (point))))
663 (calc-sel-reselect calc-keep-selection)
664 (entry (calc-top num 'entry))
665 (expr (car entry))
666 (sel (or (calc-auto-selection entry) expr))
667 alg)
668 (let ((str (math-showing-full-precision
669 (math-format-nice-expr sel (frame-width)))))
670 (calc-edit-mode (list 'calc-finish-selection-edit
671 num (list 'quote sel) calc-sel-reselect))
672 (insert str "\n"))))
673 (calc-show-edit-buffer))
674
675 (defvar calc-original-buffer)
676
677 ;; The variable calc-edit-disp-trail is local to calc-edit-finish,
678 ;; in calc-yank.el.
679 (defvar calc-edit-disp-trail)
680 (defvar calc-edit-top)
681
682 (defun calc-finish-selection-edit (num sel reselect)
683 (let ((buf (current-buffer))
684 (str (buffer-substring calc-edit-top (point-max)))
685 (start (point)))
686 (switch-to-buffer calc-original-buffer)
687 (let ((val (math-read-expr str)))
688 (if (eq (car-safe val) 'error)
689 (progn
690 (switch-to-buffer buf)
691 (goto-char (+ start (nth 1 val)))
692 (error (nth 2 val))))
693 (calc-wrapper
694 (calc-preserve-point)
695 (if calc-edit-disp-trail
696 (calc-trail-display 1 t))
697 (setq val (calc-encase-atoms (calc-normalize val)))
698 (let ((expr (calc-top num 'full)))
699 (if (calc-find-sub-formula expr sel)
700 (calc-pop-push-record-list 1 "edit"
701 (list (calc-replace-sub-formula
702 expr sel val))
703 num
704 (list (and reselect val)))
705 (calc-push val)
706 (error "Original selection has been lost")))))))
707
708 (defun calc-sel-evaluate (arg)
709 (interactive "p")
710 (calc-slow-wrapper
711 (calc-preserve-point)
712 (let* ((num (max 1 (calc-locate-cursor-element (point))))
713 (calc-sel-reselect calc-keep-selection)
714 (entry (calc-top num 'entry))
715 (sel (or (calc-auto-selection entry) (car entry))))
716 (calc-with-default-simplification
717 (let ((math-simplify-only nil))
718 (calc-modify-simplify-mode arg)
719 (let ((val (calc-encase-atoms (calc-normalize sel))))
720 (calc-pop-push-record-list 1 "jsmp"
721 (list (calc-replace-sub-formula
722 (car entry) sel val))
723 num
724 (list (and calc-sel-reselect val))))))
725 (calc-handle-whys))))
726
727 (defun calc-sel-expand-formula (arg)
728 (interactive "p")
729 (calc-slow-wrapper
730 (calc-preserve-point)
731 (let* ((num (max 1 (calc-locate-cursor-element (point))))
732 (calc-sel-reselect calc-keep-selection)
733 (entry (calc-top num 'entry))
734 (sel (or (calc-auto-selection entry) (car entry))))
735 (calc-with-default-simplification
736 (let ((math-simplify-only nil))
737 (calc-modify-simplify-mode arg)
738 (let* ((math-expand-formulas (> arg 0))
739 (val (calc-normalize sel))
740 top)
741 (and (<= arg 0)
742 (setq top (math-expand-formula val))
743 (setq val (calc-normalize top)))
744 (setq val (calc-encase-atoms val))
745 (calc-pop-push-record-list 1 "jexf"
746 (list (calc-replace-sub-formula
747 (car entry) sel val))
748 num
749 (list (and calc-sel-reselect val))))))
750 (calc-handle-whys))))
751
752 (defun calc-sel-mult-both-sides (no-simp &optional divide)
753 (interactive "P")
754 (calc-wrapper
755 (calc-preserve-point)
756 (let* ((num (max 1 (calc-locate-cursor-element (point))))
757 (calc-sel-reselect calc-keep-selection)
758 (entry (calc-top num 'entry))
759 (expr (car entry))
760 (sel (or (calc-auto-selection entry) expr))
761 (func (car-safe sel))
762 alg lhs rhs)
763 (setq alg (calc-with-default-simplification
764 (car (calc-do-alg-entry ""
765 (if divide
766 "Divide both sides by: "
767 "Multiply both sides by: ")))))
768 (and alg
769 (progn
770 (if (and (or (eq func '/)
771 (assq func calc-tweak-eqn-table))
772 (= (length sel) 3))
773 (progn
774 (or (memq func '(/ calcFunc-eq calcFunc-neq))
775 (if (math-known-nonposp alg)
776 (progn
777 (setq func (nth 1 (assq func
778 calc-tweak-eqn-table)))
779 (or (math-known-negp alg)
780 (message "Assuming this factor is nonzero")))
781 (or (math-known-posp alg)
782 (if (math-known-nonnegp alg)
783 (message "Assuming this factor is nonzero")
784 (message "Assuming this factor is positive")))))
785 (setq lhs (list (if divide '/ '*) (nth 1 sel) alg)
786 rhs (list (if divide '/ '*) (nth 2 sel) alg))
787 (or no-simp
788 (progn
789 (setq lhs (math-simplify lhs)
790 rhs (math-simplify rhs))
791 (and (eq func '/)
792 (or (Math-equal (nth 1 sel) 1)
793 (Math-equal (nth 1 sel) -1)
794 (and (memq (car-safe (nth 2 sel)) '(+ -))
795 (memq (car-safe alg) '(+ -))))
796 (setq rhs (math-expand-term rhs)))))
797 (setq alg (calc-encase-atoms
798 (calc-normalize (list func lhs rhs)))))
799 (setq rhs (list (if divide '* '/) sel alg))
800 (or no-simp
801 (setq rhs (math-simplify rhs)))
802 (setq alg (calc-encase-atoms
803 (calc-normalize (if divide
804 (list '/ rhs alg)
805 (list '* alg rhs))))))
806 (calc-pop-push-record-list 1 (if divide "div" "mult")
807 (list (calc-replace-sub-formula
808 expr sel alg))
809 num
810 (list (and calc-sel-reselect alg)))))
811 (calc-handle-whys))))
812
813 (defun calc-sel-div-both-sides (no-simp)
814 (interactive "P")
815 (calc-sel-mult-both-sides no-simp t))
816
817 (defun calc-sel-add-both-sides (no-simp &optional subtract)
818 (interactive "P")
819 (calc-wrapper
820 (calc-preserve-point)
821 (let* ((num (max 1 (calc-locate-cursor-element (point))))
822 (calc-sel-reselect calc-keep-selection)
823 (entry (calc-top num 'entry))
824 (expr (car entry))
825 (sel (or (calc-auto-selection entry) expr))
826 (func (car-safe sel))
827 alg lhs rhs)
828 (setq alg (calc-with-default-simplification
829 (car (calc-do-alg-entry ""
830 (if subtract
831 "Subtract from both sides: "
832 "Add to both sides: ")))))
833 (and alg
834 (progn
835 (if (and (assq func calc-tweak-eqn-table)
836 (= (length sel) 3))
837 (progn
838 (setq lhs (list (if subtract '- '+) (nth 1 sel) alg)
839 rhs (list (if subtract '- '+) (nth 2 sel) alg))
840 (or no-simp
841 (setq lhs (math-simplify lhs)
842 rhs (math-simplify rhs)))
843 (setq alg (calc-encase-atoms
844 (calc-normalize (list func lhs rhs)))))
845 (setq rhs (list (if subtract '+ '-) sel alg))
846 (or no-simp
847 (setq rhs (math-simplify rhs)))
848 (setq alg (calc-encase-atoms
849 (calc-normalize (list (if subtract '- '+) alg rhs)))))
850 (calc-pop-push-record-list 1 (if subtract "sub" "add")
851 (list (calc-replace-sub-formula
852 expr sel alg))
853 num
854 (list (and calc-sel-reselect alg)))))
855 (calc-handle-whys))))
856
857 (defun calc-sel-sub-both-sides (no-simp)
858 (interactive "P")
859 (calc-sel-add-both-sides no-simp t))
860
861 (provide 'calc-sel)
862
863 ;;; arch-tag: e5169792-777d-428f-bff5-acca66813fa2
864 ;;; calc-sel.el ends here