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