unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
From: Yuan Fu <casouri@gmail.com>
To: Eli Zaretskii <eliz@gnu.org>
Cc: emacs-devel <emacs-devel@gnu.org>
Subject: Re: Word wrap for non-whitespace-seperated language
Date: Thu, 5 Mar 2020 17:50:22 -0500	[thread overview]
Message-ID: <0C001A5A-B45C-43C0-9D1E-88A6977AAEC3@gmail.com> (raw)
In-Reply-To: <6DE83788-5296-4C4F-A265-88B33A43DC93@gmail.com>

[-- Attachment #1: Type: text/plain, Size: 748 bytes --]

> I have no idea if it helps (apologies, if not),
> but maybe take a look at library `find-where.el'.
> It lets you find (forward or backward) the first
> (or the Nth) buffer position where some predicate
> holds.

Thanks Adam. I actually find the way just now (by sheer luck). Now its reasonably fast.

For anyone that’s interested, here is the code. Set sfill-variale-pitch to t and M-x sfill-paragraph on a text paragraph, and see the magic happens ;-) It would be great if some one can have a look at it and give some suggestions, especially if it can be made faster. Next I want to try to make it automatic and only fills the visible portion just-in-time. Could some one point me to some library that does similar things? Thanks.


[-- Attachment #2: sfill.el --]
[-- Type: application/octet-stream, Size: 4243 bytes --]

;;; sfill.el --- Soft and smart fill      -*- lexical-binding: t; -*-

;; Author: Yuan Fu <casouri@gmail.com>

;;; This file is NOT part of GNU Emacs

;;; Commentary:
;;

;;; Code:
;;

(defvar-local sfill-column 70
  "Default fill Column for sfill.")

(defvar-local sfill-variable-pitch-column 70
  "Column used for variable pitch filling.")

(defvar-local sfill-variale-pitch nil
  "Set to non-nil and sfill will assume variable pitch when filling.")

(defface sfill-debug-face (let ((spec '(:inherit default))
                            (display t))
                        `((,display . ,spec)))
  "Face for highlighting sfill overlays."
  :group 'sfill)

(define-minor-mode sfill-debug-mode
  "Toggle debug mode for sfill."
  :lighter ""
  (if sfill-debug-mode
      (set-face-attribute 'sfill-debug-face nil :inherit 'highlight)
    (set-face-attribute 'sfill-debug-face nil :inherit 'default)))

(defun sfill-insert (string)
  "Insert STRING at point by overlay."
  ;; We shouldn’t need to break line at point-max.
  (if (or (eq (point) (point-max)))
      (error "Cannot insert at the end of visible buffer")
    (let* ((beg (point))
           (end (1+ (point)))
           (ov (make-overlay beg end)))
      (overlay-put ov 'sfill t)
      (overlay-put ov 'before-string string)
      (overlay-put ov 'evaporate t)
      (overlay-put ov 'face 'sfill-debug-face))))

(defun sfill-clear-overlay (beg end)
  "Clear overlays that `soft-insert' made between BEG and END."
  (let ((overlay-list (overlays-in beg end)))
    (dolist (ov overlay-list)
      (when (overlay-get ov 'sfill)
        (delete-overlay ov)))))

(defun sfill-clear-char (char beg end)
  "Remove CHAR(string) in the region from BEG to END."
  (save-excursion
    (goto-char beg)
    (while (re-search-forward char end t)
      ;; I can be more intelligent here, but since the break point
      ;; function is from fill.el, better keep in sync with it.
      ;; (see ‘fill-move-to-break-point’)
      (if (and (eq (char-charset (char-before (1- (point)))) 'ascii)
	       (eq (char-charset (char-after (point))) 'ascii))
          (replace-match " ")
        (replace-match "")))))

(defun sfill-forward-column (column)
  "Forward COLUMN columns."
  (while (>= column 0)
    (forward-char)
    (setq column (- column (char-width (char-before))))))

(defun sfill-forward-column-variable-pitch (column bound)
  "Forward COLUMN columns in variable pitch environment.
BOUND is point where we shouldn’t go beyond."
  ;; X offset from widow’s left edge in pixels. We want to break
  ;; around this position.
  (let* ((column-x-pos (* column (window-font-width)))
         (initial-y (cadr (pos-visible-in-window-p nil nil t))))
    (goto-char (min (posn-point (posn-at-x-y column-x-pos initial-y))
                    bound))))

(defun sfill-region (beg end)
  "Fill region between BEG and END. Assume mono space."
  (save-excursion
    (sfill-clear-overlay beg end)
    (sfill-clear-char "\n" beg end)
    (let (linebeg)
      (goto-char beg)
      (while (< (point) end)
        (setq linebeg (point))
        ;; We cannot use ‘move-to-column’ as fill.el does. Because we
        ;; break lines with overlays, so if we are at a fake newline,
        ;; ‘move-to-column’ doesn’t really go forward.
        (if sfill-variale-pitch
            (progn
              (unless (pos-visible-in-window-p)
                (recenter nil t))
              (sfill-forward-column-variable-pitch
               sfill-variable-pitch-column end))
          (sfill-forward-column sfill-column))
        ;; Check again if we are in the desired range.
        (when (< (point) end)
          (fill-move-to-break-point linebeg)
          (skip-chars-forward " \t")
          (sfill-insert "\n"))))))

(defun sfill-paragraph ()
  "Fill current paragraph."
  (interactive)
  (let (beg end)
    (save-excursion
      (backward-paragraph)
      (skip-chars-forward "\n")
      (setq beg (point))
      (forward-paragraph)
      (skip-chars-backward "\n")
      (setq end (point))
      (sfill-region beg end))))

(provide 'sfill)

;;; sfill.el ends here

[-- Attachment #3: Type: text/plain, Size: 6 bytes --]



Yuan

  parent reply	other threads:[~2020-03-05 22:50 UTC|newest]

Thread overview: 24+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-03-04 18:39 Word wrap for non-whitespace-seperated language Yuan Fu
2020-03-04 18:44 ` Eli Zaretskii
2020-03-04 18:51   ` Yuan Fu
2020-03-04 19:16     ` Eli Zaretskii
2020-03-04 20:34       ` Yuan Fu
2020-03-05  4:42         ` Eli Zaretskii
2020-03-05 22:33           ` Yuan Fu
2020-03-05 22:46             ` Drew Adams
2020-03-05 22:50             ` Yuan Fu [this message]
2020-03-06  2:18               ` Yuan Fu
2020-03-07  4:23             ` Richard Stallman
2020-03-07  5:04               ` Yuan Fu
2020-03-07  8:19                 ` Eli Zaretskii
2020-03-07 17:30                   ` Yuan Fu
2020-03-09  2:52                     ` Richard Stallman
2020-03-08  6:16                 ` Richard Stallman
2020-03-08 15:04                   ` Yuan Fu
2020-03-09  2:50                     ` Richard Stallman
2020-03-09 15:44                       ` Yuan Fu
2020-03-09 17:20                         ` Eli Zaretskii
2020-03-09 20:11                           ` Yuan Fu
2020-03-07  8:22               ` Eli Zaretskii
2020-03-07  8:40                 ` Lars Ingebrigtsen
2020-03-07 10:50                   ` Eli Zaretskii

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.gnu.org/software/emacs/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=0C001A5A-B45C-43C0-9D1E-88A6977AAEC3@gmail.com \
    --to=casouri@gmail.com \
    --cc=eliz@gnu.org \
    --cc=emacs-devel@gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).