From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.ciao.gmane.io!not-for-mail From: Yuan Fu Newsgroups: gmane.emacs.devel Subject: Re: Word wrap for non-whitespace-seperated language Date: Mon, 9 Mar 2020 11:44:51 -0400 Message-ID: <1DFB258C-A804-406F-8ADB-EE8D2782087A@gmail.com> References: <838skgvu2l.fsf@gnu.org> <3692AB81-B291-4D14-BEDE-924F020D94ED@gmail.com> <837e00vsk9.fsf@gnu.org> <9737C398-80FC-4377-91BA-C0891BD5A0F5@gmail.com> <835zfjwgyb.fsf@gnu.org> <6DE83788-5296-4C4F-A265-88B33A43DC93@gmail.com> <4E3669DB-4012-4E56-9517-F1BEB0D97A78@gmail.com> <17F1587A-CE02-4BF7-9C53-68E66FD733ED@gmail.com> Mime-Version: 1.0 (Mac OS X Mail 13.0 \(3608.60.0.2.5\)) Content-Type: multipart/mixed; boundary="Apple-Mail=_F033E8A2-D4A1-40A2-9B87-B4BCEA047B1A" Injection-Info: ciao.gmane.io; posting-host="ciao.gmane.io:159.69.161.202"; logging-data="123208"; mail-complaints-to="usenet@ciao.gmane.io" Cc: eliz@gnu.org, emacs-devel@gnu.org To: rms@gnu.org Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org Mon Mar 09 17:11:26 2020 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 1jBL01-000VyG-Vu for ged-emacs-devel@m.gmane-mx.org; Mon, 09 Mar 2020 17:11:26 +0100 Original-Received: from localhost ([::1]:46312 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jBL01-00009P-1g for ged-emacs-devel@m.gmane-mx.org; Mon, 09 Mar 2020 12:11:25 -0400 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]:40658) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jBKaT-00031C-LF for emacs-devel@gnu.org; Mon, 09 Mar 2020 11:45:02 -0400 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1jBKaR-0001my-LA for emacs-devel@gnu.org; Mon, 09 Mar 2020 11:45:01 -0400 Original-Received: from mail-qv1-xf34.google.com ([2607:f8b0:4864:20::f34]:46797) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1jBKaM-0001ky-RI; Mon, 09 Mar 2020 11:44:55 -0400 Original-Received: by mail-qv1-xf34.google.com with SMTP id m2so4541098qvu.13; Mon, 09 Mar 2020 08:44:54 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:message-id:mime-version:subject:date:in-reply-to:cc:to :references; bh=IO8GfDDCYJCLurSdrU6XN0nXPHJPoHi15JBHfQzi/yk=; b=HEU+JYNuKa+12rI2cJb0cbpDgdUP3fOrqh0SZdGpQ5AkL0eK+rUZ5JF+sNQKnX0avk VumF98zH7DMvhC60oBEp8uOZ7yU1HJYoJ+7j/54qgs+WPGBlQbWMV5aV+GCwjZGEm94H T/nzhr9+0d/vFXxz5MOaIQeKsacRy0yT01XB6gUQ8aFcuCAtjp/zmgvDUwwtiaxDW4kc GA9EdLTOtHP6V5ulZOBcUFhm8ZQPLiT3tTiYR5FStCnyCAhslUKPcOIY44r7xVaxdTA8 hLtDCjeJaJIbPuMMdW0PPKmbW0j7IBK+Q26NumUB6x0xec2OZfDYlZMU3cxlHfcgqIdD V4XQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:message-id:mime-version:subject:date :in-reply-to:cc:to:references; bh=IO8GfDDCYJCLurSdrU6XN0nXPHJPoHi15JBHfQzi/yk=; b=WlvtQvUaFGIgt9iwe3WoescFw7FVQJW7M2wH2wYX/DCeMkd+x16g+cCDB80R/WD6dH G/b5PigEV3O9Iq1IVZ13WXpAwarHbw0RgMRbp0Ria5vWvo9pwKnO5yGOT5RPSwswKuCO SWze/ySSBbgiYrHwoALMEw2VppF3kQM2e3x2WU+uNRw/V4nVW2OTOlbFZKMumPJkPtSX In5IFcFCHX/yTNQ4G9d7dZcoCZUhpRHrumcqVecMNPrDrEkW4jQyJ7lhksKoDVT7hj3V GZXL4K8lhPy0QQHbnFiY8DeLvntgG4QY2xQ+v9k/R7WGReF0bdPN3L9oDXV7+LlDH9D5 XEkg== X-Gm-Message-State: ANhLgQ3aQWYImH+R23WAOpZTn56xhMhyXmfZj2ed5SchsNk0H9T62RK5 lAcB4OV6hJ4kEO19v2FDiJlt/sM/euq/N7+d X-Google-Smtp-Source: ADFU+vtQ7/tGfGAGILtkOl91jBK93clt/azBmqlYIZqrp7RrIY4dtEGcL5A8DuuEPFOGpsyAujNp/w== X-Received: by 2002:a0c:ca0e:: with SMTP id c14mr15097041qvk.206.1583768693876; Mon, 09 Mar 2020 08:44:53 -0700 (PDT) Original-Received: from [192.168.1.5] (c-174-60-229-153.hsd1.pa.comcast.net. [174.60.229.153]) by smtp.gmail.com with ESMTPSA id z19sm9217501qts.86.2020.03.09.08.44.52 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Mon, 09 Mar 2020 08:44:53 -0700 (PDT) In-Reply-To: X-Mailer: Apple Mail (2.3608.60.0.2.5) X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 2607:f8b0:4864:20::f34 X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.23 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" Xref: news.gmane.io gmane.emacs.devel:245388 Archived-At: --Apple-Mail=_F033E8A2-D4A1-40A2-9B87-B4BCEA047B1A Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset=utf-8 >=20 >>> Without truly filling the lines, do the commands C-a, C-n, etc work = properly? >=20 >> It depends on the commands: C-n/p works fine (given >> line-move-visual is t), but C-a/e moves to the end of buffer line, >> which is the beginning/end of the paragraph in a users eyes >=20 > I was afraid it would be like that. >=20 > I suppose that the rectangle commands don't work, and C-x =3D does > something unhelpful. Is that so? What about C-x TAB? >=20 > If all the commands that ought to make sense for such text > understand how the display shows the line-wrapping, and DTRT, > I suppose that will be as good as real wrapping. Would you like to > work on that? For all the commands, the behavior of flywrap (I=E2=80=99m calling it = flywrap now) should be identical to that of normally redisplay word = wrapping: in both settings the text is just one line, but we display it = across multiple lines on screen. E.g., C-x =3D works the same, C-x TAB = only adds indentation to the beginning of the displayed =E2=80=9Cparagraph= =E2=80=9D, because that=E2=80=99s the beginning of the buffer line and = there is really only one line. So in that regard flywrap is as good as = redisplay wrapping. It=E2=80=99s much slower though (but fast enough to = use). I wrote two simple commands to go to the beginning/end of the displayed = line, they are automatically bound when flywrap-mode is on. Here is the latest version:=20 Yuan --Apple-Mail=_F033E8A2-D4A1-40A2-9B87-B4BCEA047B1A Content-Disposition: attachment; filename=flywrap.el Content-Type: application/octet-stream; x-unix-mode=0644; name="flywrap.el" Content-Transfer-Encoding: quoted-printable ;;;=20flywrap.el=20---=20Soft=20and=20smart=20fill=20=20=20=20=20=20-*-=20= lexical-binding:=20t;=20-*-=0A=0A;;=20Author:=20Yuan=20Fu=20= =0A=0A;;;=20This=20file=20is=20NOT=20part=20of=20GNU=20= Emacs=0A=0A;;;=20Commentary:=0A;;=0A;;=20This=20package=20gives=20you=20= word=20wrapping=20with=20more=20precision=20than=20the=0A;;=20default=20= one.=20The=20default=20word=20wrapping=20(=E2=80=98toggle-word-wrap=E2=80=99= )=20can=0A;;=20only=20wrap=20on=20white=20spaces=20and=20tabs,=20thus=20= is=20unable=20to=20wrap=20text=0A;;=20with=20both=20CJK=20characters=20= and=20latin=20characters=20properly.=20Also=20it=0A;;=20can=E2=80=99t=20= wrap=20on=20arbitrary=20columns.=20On=20the=20other=20hand,=0A;;=20= =E2=80=98fill-paragraph=E2=80=99=20can=20only=20work=20with=20mono=20= spaced=20fonts,=20filling=0A;;=20variable=20pitch=20font=20usually=20= gives=20sub-optimal=20result.=20(And,=20of=0A;;=20course,=20it=20= destructively=20insert=20newlines,=20which=20may=20not=20be=20what=20you=0A= ;;=20want.)=0A;;=0A;;=20This=20package=20solves=20above=20problems.=20It=20= wraps=20lines=20correctly=20no=0A;;=20matter=20the=20text=20is=20latin=20= or=20CJK=20or=20both,=20and=20no=20matter=20it=E2=80=99s=20mono=0A;;=20= spaces=20or=20variable=20pitch.=20It=20wraps=20on=20arbitrary=20columns=20= and=20it=0A;;=20handles=20kinsoku=20correctly=20(thanks=20to=20= kinsoku.el).=0A;;=0A;;=20=20=20Usage=0A;;=0A;;=20=09M-x=20flywrap-mode=20= RET=0A;;=0A;;=20=20=20Customization=0A;;=0A;;=20=E2=80=98flywrap-column=E2= =80=99.=0A=0A;;;=20Code:=0A;;=0A=0A(require=20'subr-x)=0A(require=20= 'cl-lib)=0A=0A(defvar-local=20flywrap-column=2070=0A=20=20"Fill=20Column=20= for=20flywrap.")=0A=0A;;;=20Backstage=0A=0A(defface=20flywrap-debug-face=20= (let=20((spec=20'(:inherit=20highlight))=0A=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= (display=20t))=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20`((,display=20.=20,spec)))=0A=20=20= "Face=20for=20highlighting=20flywrap=20overlays."=0A=20=20:group=20= 'flywrap)=0A=0A(define-minor-mode=20flywrap-debug-mode=0A=20=20"Toggle=20= debug=20mode=20for=20flywrap."=0A=20=20:lighter=20""=0A=20=20:global=20t=0A= =20=20(flywrap-region=20nil=20nil=20t))=0A=0A(defun=20= flywrap-insert-newline=20()=0A=20=20"Insert=20newline=20at=20point=20by=20= overlay."=0A=20=20;;=20We=20shouldn=E2=80=99t=20need=20to=20break=20line=20= at=20point-max.=0A=20=20(if=20(or=20(eq=20(point)=20(point-max)))=0A=20=20= =20=20=20=20(error=20"Cannot=20insert=20at=20the=20end=20of=20visible=20= buffer")=0A=20=20=20=20(let*=20((beg=20(point))=0A=20=20=20=20=20=20=20=20= =20=20=20(end=20(1+=20(point)))=0A=20=20=20=20=20=20=20=20=20=20=20(ov=20= (make-overlay=20beg=20end=20nil=20t)))=0A=20=20=20=20=20=20(overlay-put=20= ov=20'flywrap=20t)=0A=20=20=20=20=20=20(overlay-put=20ov=20= 'before-string=20"\n")=0A=20=20=20=20=20=20(overlay-put=20ov=20= 'evaporate=20t)=0A=20=20=20=20=20=20(when=20flywrap-debug-mode=0A=20=20=20= =20=20=20=20=20(overlay-put=20ov=20'face=20'flywrap-debug-face)))))=0A=0A= (defun=20flywrap-clear-overlay=20(beg=20end)=0A=20=20"Clear=20overlays=20= that=20`soft-insert'=20made=20between=20BEG=20and=20END."=0A=20=20(let=20= ((overlay-list=20(overlays-in=20beg=20end)))=0A=20=20=20=20(dolist=20(ov=20= overlay-list)=0A=20=20=20=20=20=20(when=20(overlay-get=20ov=20'flywrap)=0A= =20=20=20=20=20=20=20=20(delete-overlay=20ov)))))=0A=0A(defun=20= flywrap-delete-overlay-at=20(point)=0A=20=20"Delete=20flywrap=20overlay=20= at=20POINT."=0A=20=20(flywrap-clear-overlay=20point=20(1+=20point)))=0A=0A= (defun=20flywrap-unfill=20(beg=20end)=0A=20=20"Remove=20newlines=20in=20= the=20region=20from=20BEG=20to=20END."=0A=20=20(save-excursion=0A=20=20=20= =20(goto-char=20beg)=0A=20=20=20=20(while=20(re-search-forward=20"\n"=20= end=20t)=0A=20=20=20=20=20=20(unless=0A=20=20=20=20=20=20=20=20=20=20;;=20= If=20we=20are=20at=20point-max,=20=E2=80=98char-after=E2=80=99=20returns=20= nil.=0A=20=20=20=20=20=20=20=20=20=20(eq=20(point)=20(point-max))=0A=20=20= =20=20=20=20=20=20;;=20Regarding=20the=20'ascii:=20I=20can=20be=20more=20= intelligent=20here=0A=20=20=20=20=20=20=20=20;;=20(include=20iso-latin,=20= etc),=20but=20since=20the=20break=20point=20function=0A=20=20=20=20=20=20= =20=20;;=20is=20from=20fill.el,=20better=20keep=20in=20sync=20with=20it.=20= (see=0A=20=20=20=20=20=20=20=20;;=20=E2=80=98fill-move-to-break-point=E2=80= =99).=0A=20=20=20=20=20=20=20=20;;=20Don=E2=80=99t=20remove=20= consecutive=20newlines.=0A=20=20=20=20=20=20=20=20(cond=20((or=20(eq=20= (char-before=20(1-=20(point)))=20?\n)=0A=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20(eq=20(char-after=20(point))=20?\n))=0A=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20nil)=0A=20=20=20=20=20=20=20=20=20=20=20= =20=20=20;;=20Separate=20ascii=20characters=20with=20space=0A=20=20=20=20= =20=20=20=20=20=20=20=20=20=20((and=20(eq=20(char-charset=20(char-before=20= (1-=20(point))))=20'ascii)=0A=09=20=20=20=20=20=20=20=20=20=20=20=20(eq=20= (char-charset=20(char-after=20(point)))=20'ascii))=0A=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20(replace-match=20"=20"))=0A=20=20=20=20=20=20=20=20= =20=20=20=20=20=20;;=20Don=E2=80=99t=20separate=20CJK=20characters.=0A=20= =20=20=20=20=20=20=20=20=20=20=20=20=20(t=20(replace-match=20"")))))))=0A= =0A(defun=20flywrap-forward-column=20(column)=0A=20=20"Forward=20COLUMN=20= columns.=0A=0AThis=20only=20works=20correctly=20in=20mono=20space=20= setting."=0A=20=20(condition-case=20nil=0A=20=20=20=20=20=20(while=20(>=3D= =20column=200)=0A=20=20=20=20=20=20=20=20(forward-char)=0A=20=20=20=20=20= =20=20=20(setq=20column=20(-=20column=20(char-width=20(char-before)))))=0A= =20=20=20=20('end-of-buffer=20nil)))=0A=0A(defun=20= flywrap-forward-column-visual=20(column)=0A=20=20"Forward=20COLUMN=20= columns=20and=20return=20point.=0A=0AWorks=20for=20both=20mono=20space=20= and=20variable=20pitch."=0A=20=20;;=20=E2=80=98column-x-pos=E2=80=99=20= is=20the=20x=20offset=20from=20widow=E2=80=99s=20left=20edge=20in=20= pixels.=0A=20=20;;=20We=20want=20to=20break=20around=20this=20position.=0A= =20=20(condition-case=20nil=0A=20=20=20=20=20=20(let=20((column-x-pos=20= (*=20column=20(window-font-width))))=0A=20=20=20=20=20=20=20=20(while=20= (>=3D=20column-x-pos=200)=0A=20=20=20=20=20=20=20=20=20=20(forward-char)=0A= =20=20=20=20=20=20=20=20=20=20(unless=20(invisible-p=20(point))=0A=20=20=20= =20=20=20=20=20=20=20=20=20(setq=20column-x-pos=0A=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20(-=20column-x-pos=0A=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20(car=20(mapcar=0A=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20(lambda=20= (glyph)=20(aref=20glyph=204))=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20(font-get-glyphs=20(font-at=20(1-=20= (point)))=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20(1-=20= (point))(point))))))))=0A=20=20=20=20=20=20=20=20(point))=0A=20=20=20=20= ('end-of-buffer=20(point))))=0A=0A(defun=20flywrap-go-to-break-point=20= (linebeg=20bound)=0A=20=20"Move=20to=20the=20position=20where=20the=20= line=20should=20be=20broken.=0ALINEBEG=20is=20the=20beginning=20of=20= current=20visual=20line.=0AWe=20don=E2=80=99t=20go=20beyond=20BOUND."=0A=20= =20;;=20Go=20to=20roughly=20the=20right=20place=20to=20break.=0A=20=20= (if=20(display-multi-font-p)=0A=20=20=20=20=20=20= (flywrap-forward-column-visual=20flywrap-column)=0A=20=20=20=20= (flywrap-forward-column=20flywrap-column))=0A=20=20;;=20If=20this=20= (visual)=20line=20is=20the=20last=20line=20of=20the=20(visual)=20= paragraph,=0A=20=20;;=20(point)=20would=20be=20equal=20to=20bound,=20and=20= we=20want=20to=20stay=20there,=20so=0A=20=20;;=20that=20later=20we=20= don=E2=80=99t=20insert=20newline=20incorrectly.=0A=20=20(if=20(>=3D=20= (point)=20bound)=0A=20=20=20=20=20=20(goto-char=20bound))=0A=20=20;;=20= Find=20the=20RIGHT=20place=20to=20break.=0A=20=20(when=20(<=20(point)=20= bound)=0A=20=20=20=20(let=20((fill-nobreak-invisible=20t))=0A=20=20=20=20= =20=20(fill-move-to-break-point=20linebeg))=0A=20=20=20=20= (skip-chars-forward=20"=20\t")))=0A=0A(defsubst=20flywrap-next-break=20= (point=20bound)=0A=20=20"Return=20the=20position=20of=20the=20first=20= line=20break=20after=20POINT.=0ADon=E2=80=99t=20go=20beyond=20BOUND."=0A=20= =20(if=20(eq=20point=20(point-max))=0A=20=20=20=20=20=20point=0A=20=20=20= =20(next-single-char-property-change=0A=20=20=20=20=20(1+=20point)=0A=20=20= =20=20=20;;=20If=20we=20pass=20a=20bound=20larger=20than=20point-max,=0A=20= =20=20=20=20;;=20Emacs=20hangs.=0A=20=20=20=20=20'flywrap=20nil=20(min=20= bound=20(point-max)))))=0A=0A(defsubst=20flywrap-at-break=20(point)=0A=20= =20"Return=20non-nil=20if=20POINT=20is=20at=20a=20line=20break."=0A=20=20= (plist-get=20(mapcan=20#'overlay-properties=0A=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20(overlays-at=20point))=0A=20=20=20=20= =20=20=20=20=20=20=20=20=20'flywrap))=0A=0A(defsubst=20= flywrap-prev-break=20(point=20bound)=0A=20=20"Return=20the=20position=20= of=20the=20first=20line=20break=20before=20POINT.=0ADon=E2=80=99t=20go=20= beyond=20BOUND."=0A=20=20(max=20(1-=20= (previous-single-char-property-change=0A=20=20=20=20=20=20=20=20=20=20=20= =20point=20'flywrap=20nil=0A=20=20=20=20=20=20=20=20=20=20=20=20(min=20= (1+=20bound)=20(poin-min))))=0A=20=20=20=20=20=20=20(point-min)))=0A=0A= (defun=20flywrap-line=20(point=20&optional=20force)=0A=20=20"Fill=20the=20= line=20in=20where=20POINT=20is.=0AReturn=20(BEG=20END)=20where=20the=20= text=20is=20filled.=20BEG=20is=20the=20visual=0Abeginning=20of=20current=20= live.=20END=20is=20the=20actual=20end=20of=20line.=20If=0AFORCE=20is=20= non-nil,=20update=20the=20whole=20line."=0A=20=20(catch=20= 'early-termination=0A=20=20=20=20(save-window-excursion=0A=20=20=20=20=20= =20(save-excursion=0A=20=20=20=20=20=20=20=20(if=20(eq=20point=20= (point-max))=0A=20=20=20=20=20=20=20=20=20=20=20=20(throw=20= 'early-termination=20(cons=20point=20point)))=0A=20=20=20=20=20=20=20=20= (let*=20((end=20(line-end-position))=0A=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20(prev-break=20(if=20(flywrap-at-break=20point)=20point=0A=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20(flywrap-prev-break=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20point=20= (line-beginning-position))))=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20(prev-break=20(flywrap-prev-break=0A=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20prev-break=20= (line-beginning-position)))=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= next-existing-break=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20(beg=20= prev-break)=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20(match-count=20= 0))=0A=20=20=20=20=20=20=20=20=20=20(goto-char=20beg)=0A=20=20=20=20=20=20= =20=20=20=20(while=20(<=20(point)=20end)=0A=20=20=20=20=20=20=20=20=20=20= =20=20(setq=20next-existing-break=20(flywrap-next-break=20(point)=20= end))=0A=20=20=20=20=20=20=20=20=20=20=20=20(flywrap-delete-overlay-at=20= next-existing-break)=0A=20=20=20=20=20=20=20=20=20=20=20=20= (flywrap-go-to-break-point=20(point)=20end)=0A=20=20=20=20=20=20=20=20=20= =20=20=20(unless=20(>=3D=20(point)=20end)=0A=20=20=20=20=20=20=20=20=20=20= =20=20=20=20(flywrap-insert-newline))=0A=20=20=20=20=20=20=20=20=20=20=20= =20(if=20(eq=20next-existing-break=20(point))=0A=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20(setq=20match-count=20(1+=20match-count)))=0A=20=20=20= =20=20=20=20=20=20=20=20=20(if=20(and=20(not=20force)=20(>=3D=20= match-count=202))=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= (throw=20'early-termination=20(cons=20beg=20end))))=0A=20=20=20=20=20=20=20= =20=20=20(cons=20beg=20end))))))=0A=0A(defun=20flywrap-region=20= (&optional=20beg=20end=20force)=0A=20=20"Fill=20each=20line=20in=20the=20= region=20from=20BEG=20to=20END.=0A=0AIf=20FORCE=20is=20non-nil,=20update=20= the=20whole=20line.=20BEG=20and=20END=20default=0Ato=20beginning=20and=20= end=20of=20the=20buffer."=0A=20=20(save-excursion=0A=20=20=20=20= (goto-char=20(or=20beg=20(point-min)))=0A=20=20=20=20(flywrap-line=20= (point)=20force)=0A=20=20=20=20(while=20(re-search-forward=20"\n"=20(or=20= end=20(point-max))=20t)=0A=20=20=20=20=20=20(flywrap-line=20(point)=20= force))=0A=20=20=20=20(cons=20(or=20beg=20(point-min))=20(or=20end=20= (point-max)))))=0A=0A;;=20(defun=20flywrap-paragraph=20()=0A;;=20=20=20= "Fill=20current=20paragraph."=0A;;=20=20=20(interactive)=0A;;=20=20=20= (let=20(beg=20end)=0A;;=20=20=20=20=20(save-excursion=0A;;=20=20=20=20=20= =20=20(backward-paragraph)=0A;;=20=20=20=20=20=20=20(skip-chars-forward=20= "\n")=0A;;=20=20=20=20=20=20=20(setq=20beg=20(point))=0A;;=20=20=20=20=20= =20=20(forward-paragraph)=0A;;=20=20=20=20=20=20=20(skip-chars-backward=20= "\n")=0A;;=20=20=20=20=20=20=20(setq=20end=20(point))=0A;;=20=20=20=20=20= =20=20(flywrap-region-destructive=20beg=20end))))=0A=0A(defun=20= flywrap-unwrap=20(&optional=20beg=20end)=0A=20=20"Un-fill=20region=20= from=20BEG=20to=20END,=20default=20to=20whole=20buffer."=0A=20=20= (flywrap-clear-overlay=20(or=20beg=20(point-min))=20(or=20end=20= (point-max))))=0A=0A(defun=20flywrap-jit-lock-fn=20(beg=20end)=0A=20=20= "Fill=20line=20in=20region=20between=20BEG=20and=20END."=0A=20=20(cons=20= 'jit-lock-bounds=20(flywrap-region=20beg=20end)))=0A=0A;;=20Currently=20= not=20used.=0A(defun=20flywrap-after-change-fn=20(beg=20_=20_)=0A=20=20= "Hook=20called=20after=20buffer=20content=20change.=0ASee=20= =E2=80=98after-change-functions=E2=80=99=20for=20explanation=20on=20BEG=20= END=20LEN."=0A=20=20(flywrap-region=20beg=20(line-end-position))=0A=20=20= ;;=20(if=20(eq=20(-=20end=20beg)=201)=0A=20=20;;=20=20=20=20=20;;=20Self=20= insert=20command,=20only=20wrap=20on=20space=0A=20=20;;=20=20=20=20=20= (when=20(member=20(char-after=20beg)=20'(?\s=20?=EF=BC=8C=20?=E3=80=82=20= ?=E3=80=81))=0A=20=20;;=20=20=20=20=20=20=20(flywrap-region=20beg=20= (line-end-position)))=0A=20=20;;=20=20=20(flywrap-region=20beg=20= (line-end-position)))=0A=20=20)=0A=0A;;;=20Userland=0A=0A(defun=20= flywrap-move-end-of-line=20(&optional=20arg)=0A=20=20"Move=20to=20the=20= end=20of=20current=20visual=20line.=0A=0AWith=20argument=20ARG=20not=20= nil,=20move=20to=20the=20next=20ARG=20line=20end."=0A=20=20(interactive=20= "^p")=0A=20=20(let=20((arg=20(or=20arg=201))=0A=20=20=20=20=20=20=20=20= (point=20(point)))=0A=20=20=20=20;;=20This=20way=20hitting=20C-e=20at=20= (visual)=20EOL=20doesn=E2=80=99t=20move=20to=20next=20line.=0A=20=20=20=20= (if=20(flywrap-at-break=20(1+=20point))=0A=20=20=20=20=20=20=20=20(setq=20= point=20(1-=20point)))=0A=20=20=20=20(while=20(>=20arg=200)=0A=20=20=20=20= =20=20(setq=20point=20(flywrap-next-break=20point=20(1+=20= (line-end-position))))=0A=20=20=20=20=20=20(setq=20arg=20(1-=20arg)))=0A=20= =20=20=20(goto-char=20(1-=20point))))=0A=0A(defun=20= flywrap-move-beginning-of-line=20(arg)=0A=20=20"Move=20to=20the=20= beginning=20of=20current=20visual=20line.=0A=0AWith=20argument=20ARG=20= not=20nil,=20move=20to=20the=20previous=20ARG=20line=20beginning."=0A=20=20= (interactive=20"^p")=0A=20=20(let=20((arg=20(or=20arg=201))=0A=20=20=20=20= =20=20=20=20(point=20(point)))=0A=20=20=20=20;;=20This=20way=20hitting=20= C-a=20at=20(visual)=20BOL=20doesn=E2=80=99t=20move=20to=20previous=20= line.=0A=20=20=20=20(if=20(flywrap-at-break=20point)=0A=20=20=20=20=20=20= =20=20(setq=20point=20(+=202=20point)))=0A=20=20=20=20(while=20(>=20arg=20= 0)=0A=20=20=20=20=20=20(setq=20point=20(flywrap-prev-break=20point=20= (line-beginning-position)))=0A=20=20=20=20=20=20(setq=20arg=20(1-=20= arg)))=0A=20=20=20=20(goto-char=20point)))=0A=0A(defvar=20= flywrap-mode-map=0A=20=20(let=20((map=20(make-sparse-keymap)))=0A=20=20=20= =20(define-key=20map=20(kbd=20"C-a")=20#'flywrap-move-beginning-of-line)=0A= =20=20=20=20(define-key=20map=20(kbd=20"C-e")=20= #'flywrap-move-end-of-line)=0A=20=20=20=20map)=0A=20=20"The=20keymap=20= for=20minor=20mode=20=E2=80=98flywrap-mode=E2=80=99.")=0A=0A= (define-minor-mode=20flywrap-mode=0A=20=20"Automatically=20wrap=20= lines."=0A=20=20:lighter=20""=0A=20=20:keymap=20'flywrap-mode-map=0A=20=20= (if=20flywrap-mode=0A=20=20=20=20=20=20(progn=0A=20=20=20=20=20=20=20=20= ;;=20We=20want=20to=20control=20the=20depth=20of=20= =E2=80=98flywrap-jit-lock-fn=E2=80=99=20so=20it=0A=20=20=20=20=20=20=20=20= ;;=20runs=20hopefully=20after=20other=20functions.=20For=20example,=20= let=20Org=0A=20=20=20=20=20=20=20=20;;=20mode=E2=80=99s=20fortifier=20to=20= add=20invisible=20property=20(for=20links,=20etc)=0A=20=20=20=20=20=20=20= =20;;=20before=20we=20wrap=20lines.=0A=20=20=20=20=20=20=20=20(add-hook=20= 'jit-lock-functions=20#'flywrap-jit-lock-fn=2090=20t)=0A=20=20=20=20=20=20= =20=20;;=20Fix=20problem=20with=20incorrect=20wrapping=20when=20unfold=20= a=20org=0A=20=20=20=20=20=20=20=20;;=20header.=0A=20=20=20=20=20=20=20=20= (advice-add=20#'org-flag-region=20:after=0A=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20(lambda=20(from=20to=20_=20_1)=20(when=20= flywrap-mode=0A=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= (flywrap-region=20from=20to))))=0A=20=20=20=20=20=20=20=20= (jit-lock-refontify))=0A=20=20=20=20(jit-lock-unregister=20= #'flywrap-jit-lock-fn)=0A=20=20=20=20(flywrap-unwrap)))=0A=0A(provide=20= 'flywrap)=0A=0A;;;=20flywrap.el=20ends=20here=0A= --Apple-Mail=_F033E8A2-D4A1-40A2-9B87-B4BCEA047B1A Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset=us-ascii --Apple-Mail=_F033E8A2-D4A1-40A2-9B87-B4BCEA047B1A--