From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.blaine.gmane.org!not-for-mail From: Emanuel Berg Newsgroups: gmane.emacs.devel Subject: [Elisp: 8 out of 10 problems] I think the last one! (point) Date: Sun, 11 Aug 2024 02:14:43 +0200 Message-ID: <875xs7zzik.fsf@dataswamp.org> Mime-Version: 1.0 Content-Type: text/plain Injection-Info: ciao.gmane.io; posting-host="blaine.gmane.org:116.202.254.214"; logging-data="4609"; mail-complaints-to="usenet@ciao.gmane.io" User-Agent: Gnus/5.13 (Gnus v5.13) To: emacs-devel@gnu.org Cancel-Lock: sha1:I4X+wJ0MTXFBtdoJHRKYQGNzvQo= Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org Sun Aug 11 06:28:56 2024 Return-path: Envelope-to: ged-emacs-devel@m.gmane-mx.org Original-Received: from lists.gnu.org ([209.51.188.17]) by ciao.gmane.io with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1sd0CN-00010X-Mk for ged-emacs-devel@m.gmane-mx.org; Sun, 11 Aug 2024 06:28:55 +0200 Original-Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1sd0C4-0004ju-Pa; Sun, 11 Aug 2024 00:28:37 -0400 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1scwEZ-0006Lh-6m for emacs-devel@gnu.org; Sat, 10 Aug 2024 20:14:55 -0400 Original-Received: from ciao.gmane.io ([116.202.254.214]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1scwEW-0007S9-EY for emacs-devel@gnu.org; Sat, 10 Aug 2024 20:14:54 -0400 Original-Received: from list by ciao.gmane.io with local (Exim 4.92) (envelope-from ) id 1scwEU-0007Tb-Bm for emacs-devel@gnu.org; Sun, 11 Aug 2024 02:14:50 +0200 X-Injected-Via-Gmane: http://gmane.org/ Mail-Followup-To: emacs-devel@gnu.org Mail-Copies-To: never Received-SPF: pass client-ip=116.202.254.214; envelope-from=ged-emacs-devel@m.gmane-mx.org; helo=ciao.gmane.io X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, HEADER_FROM_DIFFERENT_DOMAINS=0.001, RCVD_IN_VALIDITY_CERTIFIED_BLOCKED=0.001, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-Mailman-Approved-At: Sun, 11 Aug 2024 00:28:34 -0400 X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org Original-Sender: emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org Xref: news.gmane.io gmane.emacs.devel:322627 Archived-At: ---------------------------------------------------------------------- Part 10: https://lists.gnu.org/archive/html/emacs-devel/2024-08/msg00154.html Part 9: https://lists.gnu.org/archive/html/emacs-devel/2024-08/msg00380.html ---------------------------------------------------------------------- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ $ NOTE: Okay, I'll do the whole list then! No one should say, I am all % ~~~~~~. the time just complaining very vaguely, no specifics, no code, % % no suggestions, not taking any risks. Who came up with it? But % % it isn't true and this list shows it. But I'll write shorter, % % christ, damn Russian novel, this. Or maybe this will be my me % % last post as I've written 3 already, everyone can see that. % ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ We have heard that in Emacs everything is done in the buffer. This can be taken literally and figuratively. If we literally instead say we can do a lot in the buffers, editing as well as automatic, then everyone is cool with that, I think. But some people have taken it too far and this is described in Part 10 above with ispell.el. However, here is an interesting thing! If we say that is part of who we are, we base are game on that, why don't we have better commands for moving around in source. Take a look again at ispell.el. That function is called `ispell-process-line'. Man, what kind of #@&%$ lines to they have! It is insane. But also look closer at the code. Point is constantly moving. Yet it is a haystack. (I removed comments.) (let ((word-start (copy-marker (+ ispell-start -1 (car (cdr poss))))) (word-len (length (car poss))) (line-end (copy-marker ispell-end)) (line-start (copy-marker ispell-start)) recheck-region replace) (goto-char word-start) (ispell-horiz-scroll) (goto-char (+ word-len word-start)) (ispell-horiz-scroll) (goto-char word-start) (ispell-horiz-scroll) (or (ispell-looking-at (car poss)) ...)) So if moving around the buffer is so important to us, why haven't we made it into an art of perfection decades ago? TBH reading that code makes me dizzy! It is like a parody of Elisp (let* ((ispell-pipe-word (car poss)) (actual-point (marker-position word-start)) (actual-line (line-number-at-pos actual-point)) (actual-column (save-excursion (goto-char actual-point) (current-column)))) (ispell-print-if-debug "ispell-process-line: Ispell misalignment error: [Word from ispell pipe]: [%s], actual (point,line,column): (%s,%s,%s)\n" ispell-pipe-word actual-point actual-line actual-column) (error (concat "Ispell misalignment: word " "`%s' point %d; probably incompatible versions") ispell-pipe-word actual-point)) What should we do? We have it to some degree, but more and more consistent and short, always. For every unit in Emacs that we know of, e.g. buffer, line, region, paragraph, word, there should be a two sets of functions. (word-beg) (word-len) (word-reg) (word-end) So same with sentence then, as 'sent-' - "sentence-" is too long. (sent-beg) (sent-len) (sent-reg) (sent-end) This should mean _go there_ But there should be another set as well, that just reports the position. This set can mirror the former but let's start from the other end to avoid typos and make it easier to see. (pos-sent-beg) (pos-sent-len) (pos-sent-reg) (pos-sent-end) There are good functions in Elisp, e.g. (pos-bol 0) and you can do (pos-eol 2) to advance one line and check. Good, short, neat and sweet. The only thing I would wish for with them, is that they would indicate what column graphically, for just one second, one called where it is visible.. However there is a lot of this. But that i neat, right? It doesn't look bad but still, must be a better way than to have every 3 out of 5 commands be about moving around point? One example that we really have under-prioritized this, is as simple as the most common of all, namely (goto-char (point-min)) But as you see that isn't optimized one bit. It is long to type, and not atomic, it is nested even. Yuk! Instead we should have, again, something like (buf-beg) (buf-len) (buf-reg) (buf-end) all with implicity `goto-char' and (pos-buf-beg) (pos-buf-reg) (pos-buf-end) is my suggestion, anyway! This is a pretty big problem, don't think it is trivial. Who is gonna want to maintain code, that is endlessly moving point around, in those super-long functions, very vaguely at any point having anything to do with the interesting problems, one thought one would solve? Not me. Looks to boring and difficult to see the buffer constantly in my head. When I program I don't want to think of the buffer. But I've done all that myself as well, of course. (I have 86 `point-min' in my source.) So annoying thing number 8, even tho this is our game plan and we have a lot, it doesn't seem like we have really optimized this for speed, brevity and code clearness. I know that some of you guys can read that fluently, cool in a way but ... is that really interesting? Why? No, reduce, reduce, reduce from code, with new syntax, old syntax, smartness, new functions, less a few more lines of Elisp, more idiomatic with libraries, and just do everything to make the damn point stay put at least sometimes. At the same time, more, more consistent, and _shorter_ functions to move it around. This kind of stuff, yeah, compare to how long I type each line! (progn (forward-paragraph -2) (when (eobp) (point))) (How to avoid it altogether is another question, and a good one. But here we care about the code, only.) END OF TRANSMISSION (goto-char (point-min)) (while (not (eobp)) (if (search-forward "<" nil t) (progn (forward-char -1) (setq result (xml-parse-tag-1 parse-dtd parse-ns)) (cond ((null result) ;; Not looking at an xml start tag. (unless (eobp) (forward-char 1))) ((and xml (not xml-sub-parser)) ;; Translation of rule [1] of XML specifications (error "XML: (Not Well-Formed) Only one root tag allowed")) ((and (listp (car result)) parse-dtd) (setq dtd (car result)) (if (cdr result) ; possible leading comment (push (cdr result) xml))) (t (push result xml)))) (goto-char (point-max)))) And now, more ispell.el: Returns a cons cell where the `car' is sum SHIFT due to changes in word replacements, and the `cdr' is the location of the final word that was queried about." ;;(declare special ispell-start ispell-end) (let (poss accept-list max-word) (if (not (numberp shift)) (setq shift 0)) ;; send string to spell process and get input. (ispell-send-string string) (while (progn (ispell-accept-output) ;; Last item of output contains a blank line. (not (string= "" (car ispell-filter))))) ;; parse all inputs from the stream one word at a time. ;; Place in FIFO order and remove the blank item. (setq ispell-filter (nreverse (cdr ispell-filter))) (while (and (not ispell-quit) ispell-filter) ;; get next word, accounting for accepted words and start shifts (setq poss (ispell-parse-output (car ispell-filter) accept-list shift)) (if (and poss (listp poss)) ; spelling error occurred. ;; Whenever we have misspellings, we can change ;; the buffer. Keep boundaries as markers. ;; Markers can move with highlighting! This destroys ;; end of region markers line-end and ispell-region-end (let ((word-start ;; There is a -1 offset here as the string is escaped ;; with '^' to prevent us accidentally sending any ;; ispell commands. (copy-marker (+ ispell-start -1 (car (cdr poss))))) (word-len (length (car poss))) (line-end (copy-marker ispell-end)) (line-start (copy-marker ispell-start)) recheck-region replace) (goto-char word-start) ;; Adjust the horizontal scroll & point (ispell-horiz-scroll) (goto-char (+ word-len word-start)) (ispell-horiz-scroll) (goto-char word-start) (ispell-horiz-scroll) ;; Alignment cannot be tracked and this error will occur when ;; `query-replace' makes multiple corrections on the starting line. (or (ispell-looking-at (car poss)) ;; This error occurs due to filter pipe problems (let* ((ispell-pipe-word (car poss)) (actual-point (marker-position word-start)) (actual-line (line-number-at-pos actual-point)) (actual-column (save-excursion (goto-char actual-point) (current-column)))) (ispell-print-if-debug "ispell-process-line: Ispell misalignment error: [Word from ispell pipe]: [%s], actual (point,line,column): (%s,%s,%s)\n" ispell-pipe-word actual-point actual-line actual-column) (error (concat "Ispell misalignment: word " "`%s' point %d; probably incompatible versions") ispell-pipe-word actual-point))) (setq max-word (marker-position word-start)) ;; ispell-cmd-loop can go recursive & change buffer (if ispell-keep-choices-win (setq replace (ispell-command-loop (car (cdr (cdr poss))) (car (cdr (cdr (cdr poss)))) (car poss) (marker-position word-start) (+ word-len (marker-position word-start)))) (save-window-excursion (setq replace (ispell-command-loop (car (cdr (cdr poss))) (car (cdr (cdr (cdr poss)))) (car poss) (marker-position word-start) (+ word-len (marker-position word-start)))))) (goto-char word-start) ;; Recheck when query replace edit changes misspelled word. ;; Error in tex mode when a potential math mode change exists. (if (and replace (listp replace) (= 2 (length replace))) (if (and (eq ispell-parser 'tex) (string-match "[\\][]()[]\\|\\\\begin\\|\\$" (regexp-quote string))) (error "Don't start query replace on a line with math characters" ) (set-marker line-end (point)) (setq ispell-filter nil recheck-region t))) ;; Insert correction if needed. (cond ((or (null replace) (equal 0 replace)) ; ACCEPT/INSERT (if (equal 0 replace) ; BUFFER-LOCAL DICT ADD (ispell-add-per-file-word-list (car poss))) ;; Do not recheck accepted word on this line. (setq accept-list (cons (car poss) accept-list))) (t ; Replacement word selected or entered. (delete-region (point) (+ word-len (point))) (if (not (listp replace)) (progn (insert replace) ; Insert dictionary word. (ispell-send-replacement (car poss) replace) (setq accept-list (cons replace accept-list))) (let ((replace-word (car replace))) ;; Recheck hand entered replacement word. (insert replace-word) (ispell-send-replacement (car poss) replace-word) (if (car (cdr replace)) (save-window-excursion (delete-other-windows) ; to correctly show help. ;; Assume case-replace & ;; case-fold-search correct? (query-replace (car poss) (car replace) t))) (goto-char word-start) ;; Do not recheck if already accepted. (if (member replace-word accept-list) (setq accept-list (cons replace-word accept-list) replace replace-word) (let ((region-end (copy-marker ispell-region-end))) (setq recheck-region ispell-filter ispell-filter nil ; Save filter. shift 0 ; Already accounted. shift (ispell-region word-start (+ word-start (length replace-word)) t shift)) (if (null shift) ; Quitting check. (setq shift 0)) (set-marker ispell-region-end region-end) (set-marker region-end nil) (setq ispell-filter recheck-region recheck-region nil replace replace-word))))) (setq shift (+ shift (- (length replace) word-len))))) (if (not ispell-quit) (let (message-log-max) (message "Continuing spelling check using %s with %s dictionary..." (file-name-non directory ispell-program-name) (or ispell-current-dictionary "default")))) (sit-for 0) (setq ispell-start (marker-position line-start) ispell-end (marker-position line-end)) ;; Adjust markers when end of region lost from highlighting. (if (and (not recheck-region) (< ispell-end (+ word-start word-len))) (setq ispell-end (+ word-start word-len))) (if (= word-start ispell-region-end) (set-marker ispell-region-end (+ word-start word-len))) ;; Going out of scope - unneeded. (set-marker line-start nil) (set-marker word-start nil) (set-marker line-end nil))) ;; Finished with misspelling! (setq ispell-filter (cdr ispell-filter))) (cons shift max-word))) -- underground experts united https://dataswamp.org/~incal