From mboxrd@z Thu Jan 1 00:00:00 1970 Path: main.gmane.org!not-for-mail From: Oliver Scholz Newsgroups: gmane.emacs.devel Subject: Re: enriched-mode and switching major modes. Date: Sat, 18 Sep 2004 18:57:13 +0200 Sender: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Message-ID: References: <200409042358.i84Nwjt19152@raven.dms.auburn.edu> <87llfn5ihw.fsf@emacswiki.org> NNTP-Posting-Host: deer.gmane.org Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" X-Trace: sea.gmane.org 1095526731 8796 80.91.229.6 (18 Sep 2004 16:58:51 GMT) X-Complaints-To: usenet@sea.gmane.org NNTP-Posting-Date: Sat, 18 Sep 2004 16:58:51 +0000 (UTC) Cc: boris@gnu.org, alex@emacswiki.org, emacs-devel@gnu.org Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Sat Sep 18 18:58:39 2004 Return-path: Original-Received: from lists.gnu.org ([199.232.76.165]) by deer.gmane.org with esmtp (Exim 3.35 #1 (Debian)) id 1C8iXE-0005Tc-00 for ; Sat, 18 Sep 2004 18:58:06 +0200 Original-Received: from localhost ([127.0.0.1] helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.33) id 1C8icp-0000M8-ML for ged-emacs-devel@m.gmane.org; Sat, 18 Sep 2004 13:03:51 -0400 Original-Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.33) id 1C8ice-0000Ja-Dh for emacs-devel@gnu.org; Sat, 18 Sep 2004 13:03:40 -0400 Original-Received: from exim by lists.gnu.org with spam-scanned (Exim 4.33) id 1C8icc-0000HU-4w for emacs-devel@gnu.org; Sat, 18 Sep 2004 13:03:39 -0400 Original-Received: from [199.232.76.173] (helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.33) id 1C8icb-0000Gx-TL for emacs-devel@gnu.org; Sat, 18 Sep 2004 13:03:37 -0400 Original-Received: from [213.165.64.20] (helo=mail.gmx.net) by monty-python.gnu.org with smtp (Exim 4.34) id 1C8iWi-0007sr-En for emacs-devel@gnu.org; Sat, 18 Sep 2004 12:57:33 -0400 Original-Received: (qmail 32539 invoked by uid 65534); 18 Sep 2004 16:57:28 -0000 Original-Received: from dsl-082-082-146-092.arcor-ip.net (EHLO USER-2MOEN8BWBA.gmx.de) (82.82.146.92) by mail.gmx.net (mp019) with SMTP; 18 Sep 2004 18:57:28 +0200 X-Authenticated: #1497658 Original-To: rms@gnu.org In-Reply-To: (Richard Stallman's message of "Fri, 17 Sep 2004 19:22:56 -0400") X-Attribution: os X-Face: "HgH2sgK|bfH$; PiOJI6|qUCf.ve<51_Od(%ynHr?=>znn#~#oS>",F%B8&\vus),2AsPYb -n>PgddtGEn}s7kH?7kH{P_~vu?]OvVN^qD(L)>G^gDCl(U9n{:d>'DkilN!_K"eNzjrtI4Ya6; Td% IZGMbJ{lawG+'J>QXPZD&TwWU@^~A}f^zAb[Ru;CT(UA]c& User-Agent: Gnus/5.1006 (Gnus v5.10.6) Emacs/21.3.50 (windows-nt) X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.5 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.org@gnu.org Xref: main.gmane.org gmane.emacs.devel:27232 X-Report-Spam: http://spam.gmane.org/gmane.emacs.devel:27232 --=-=-= Richard Stallman writes: [...] > Instead the user says: "This piece of text is a paragraph, because > I hit RET when I finished writing it. I want it to be a paragraph > of the type "Standard Text". I want "Standard Text" paragraphs to > be indented on the left by 1 cm and to have a font size of 10 pt. > Exept here, I want this paragraph to have an indentation of 2 cm." > > Now you're talking about the user interface concepts. That too is > distinct from the question of representing text inside Emacs. The > Emacs text representation needs to include a representation of the > specification of a type of paragraph, in order to implement this user > interface. Exactly! However, it is important to discuss implementation issues together with the user interface concepts in order to account for the semantics of the representation. > But it also needs to have spaces in the buffer where there is > indentation, so as to be compatible with how the whole Emacs Lisp > world understands indentation. This is where I disagree. The box model I was talking about is an abstact model, it can be implemented by different means. For instance, its left margin can indeed be implemented by spaces. I have been working with nothing but that so far. So, to a certain extent, I agree with you here. But a few notes: - The semantics of space characters used to implement a box model and space chars used for indentation in a non-WP Emacs buffer (like in this message buffer in this paragraph) are different. The former don't belong to the abstract document, they are only a means of rendering it visually. The latter are both part of the abstract document (the text/plain e-mail) and of its visual representation, because for text/plain there is no meaningful difference between both. Because of this semantic difference, existing Emacs Lisp functions would not do the right thing when working on them. I wouldn't expect them either to do the right thing. `fill-paragraph' does not work well in a dired buffer. `query-replace' does not work in a Gnus *group* buffer. - Even when working with space characters for indentation, it would probably not be as you seem to expect. When working on a graphical user interface, we would have to deal with proportional fonts of varying sizes. This is what people expect from a word processor. For this reason, all implementation techniques I have examined so far work by putting a single space character with a display property specifying the indentation column in canonical character units. Like this: (progn (switch-to-buffer (generate-new-buffer "*tmp*")) (insert (propertize " " 'display '(space :align-to 20))) (insert (propertize "lirum larum" 'face '(face :height 140 :inherit variable-pitch)))) Lisp functions, not intentionally written to deal with paragraphs in a WP buffer, would not expect this. The reason being that proportional fonts are up to today are hardly used in Emacs. (I might add, that it is also rather a bit tedious to use them without a box model supported by the display engine ...) - Implementing a box model by means of space and newline characters works for some common cases, but it doesn't scale well to the full capabilities of all abstract documents that can be expressed by various formats. I already mentioned tables as a point where it does not scale at all. But if we want to implement XML/HTML + CSS (and I definitely want), then some nested boxes with borders and background colours are not possible to display, but it would be an understatement that implementing a way to let the user interact with them (for example by typing text) would be "difficult". It is not that I have not tried ... I don't worry about that much yet! I am content with implementing a box model by means of space and newline characters for now. The Emacs word processor can do useful work without it. If I am not able to hack the display engine, then that's life. The Emacs word processor can do useful work without it. That's why I talked about "in the long run", meaning: years. But it won't be complete! I am not religious about the particular implementation of a box model! All I do care about are the design principles of WP functionality. I must say that I have felt very frustrated in the last days, because it seemed to me that we have a fundamental disagreement about concepts and design principles. Right now I am not sure. Maybe what you called a "hybrid solution" would be perfectly in order, depending on the specific features that you have in mind. Maybe we should discuss this on a concrete implementation. I have assembled a quick example from (now abandoned) code that I have written almost a year ago: --=-=-= Content-Type: application/emacs-lisp Content-Disposition: attachment; filename=wp-example.el Content-Transfer-Encoding: 8bit (eval-when-compile (require 'cl)) ;; "epos" as in "poion se epos phygen erkos odonton" (Homer) -- "which ;; word has escaped the fence of your teeth!" (defstruct epos-char-properties ;; animation-type ; animtextN ;; accnone, accdot, acccomma? bold ; b ;; all-capitals ; caps; how to implement? bg-colour ; cbN ;; `cchs' is meaningless for us. We handle character conversion ;; separately when reading and writing to a file. fg-colour ; cfN character-scaling ; charscalexN stylesheet ; csN ;; cgrid? g? gcw? gridtbl? deleted ; deleted ;; FIXME: consider a separate data structure for the revision ;; tracking feature ascent ; dnN, ;; emboss? ;; expndN? expndtwN? fittextN? font ; fN height ; fs italic ; i ;; impr? ;; kerningN? ;; FIXME: What to do with the language stuff? ;; nosupersub is handled by `ascent' ;; nosectexpand? ;; outl not possible ;; How to implement scaps? underlined ; ul, uld etc. ;; values for `underlined' are `continuous' or nil. We have no ;; means to display the various other types of underlining yet. ;; upN (superscript) is handled by `ascent' ;; v? webhidden? ) (defstruct epos-paragraph-properties ;; spv ? hyphenation ; hyphpar part-of-table ; intbl keep-intact ; keep keep-with-next ; keepn outline-level ; levelN no-line-numbering ; noline ;; widow/orphan control ? ;; outlinelevelN ? What's the difference to "levelN"? page-break-before ; pagebb ;; sbys ? stylesheet ; s ;; `stylesheet' in stylesheets denotes the base stylesheet ;; table-specific properties character-formatting alignment ;; values for `alignment' are: ;; `centered' (qc) ;; `justified' (qj) ;; `left-aligned' (ql) ;; `right-aligned' (qr) ;; qd, qkN, qt ? ;; font-alignment? first-line-indentation ;; fiN, cufiN left-indentation ; liN; what about linN and culiN? right-indentation ; ri; what about rinN and curiN? ;; adjustright? space-before ; sbN space-after ; saN ;; sbautoN? saautoN? ;; line-spacing not possible ;; nosnaplinegrid? ;; sub-documents? ;; bidi? ;; asian typography? ;; collapsed? ;; FIXME: Tabs not yet implemented. ;; FIXME: Bullets and numbering not yet implemented. ;; Borders not feasible. ;; Shading not feasible. ;; Positioned objects and frames not feasible. next-paragraph-style ) ;; FIXME: section formatting properties and document formatting ;; properties are missing. ;; Emacs' faces and RTF's character formatting style sheets have some ;; properties in common. Unfortunately they differ in some aspects. ;; For now we store faces in the font-table, because I am lazy. But ;; this needs more thought. For example, a user might want to wish to ;; specify that some exotic font she is using, is a "swiss" font, so ;; that another reader my chose something appropriate. Also we need a ;; way to specify alternative fonts. Maybe we should handle the whole ;; issue entirely without faces (using faces only when character ;; formatting properties are resolved), but I feel uneasy about it. (defface epos-serif-face '((((type x)) (:family "adobe-times")) (((type w32)) (:family "Times New Roman"))) "Basic face with variable width font.") (defface epos-sans-serif-face '((((type x)) (:family "adobe-helvetica")) (((type w32)) (:family "Arial"))) "Basic face with variable width font.") (defvar epos-font-translation-alist ;; FIXME: this needs to become a defcustom. Remember updating ;; `epos-default-font-table' accordingly. '((roman . epos-serif-face) (swiss . epos-sans-serif-face) ;; FIXME: decor, tech ... etc. )) (defvar epos-font-table nil "Table of fonts used in a document.") (make-variable-buffer-local 'epos-font-table) (defvar epos-default-font-table ;; FIXME: this needs to become a defcustom (vector 'epos-serif-face 'epos-sans-serif-face) "Default font table.") (defvar epos-paragraph-stylesheet-alist nil ;; FIXME: consider making this a hash table. "Named paragraph stylesheets. This is an alist. Each key is a stylesheet name (a string); the key is a struct `epos-paragraph-properties' specifying defaults for that stylesheet.") ;; FIXME: implement stylesheets for character formatting properties, ;; document f. p. and section f. p. ;; The whole handling of paragraph stylesheets needs more thought. We ;; probably want to display them differently on a tty, for example. ;; Maybe we need something similar to `defface'. (defvar epos-paragraph-stylesheet-defaults ;; FIXME: needs to be a defcustom `(("Headline 1" . ,(make-epos-paragraph-properties :space-before 1.0 :space-after 0.5 :next-paragraph-style "Standard" :character-formatting (make-epos-char-properties :font 1 :height 1.5))) ("Standard" . ,(make-epos-paragraph-properties :first-line-indentation 4 :next-paragraph-style "Standard" :character-formatting (make-epos-char-properties :font 0)))) "Default paragraph stylesheets.") (defvar epos-colour-table nil "Table of colours used in an RTF document.") (make-variable-buffer-local 'epos-colour-table) (defvar epos-default-colour-table ;; FIXME: needs to be a defcustom. (vector nil (face-foreground 'default) "Blue") "Default colour table.") (define-derived-mode epos-mode text-mode "Epos" "FIXME" (set (make-local-variable 'fill-paragraph-function) 'epos-fill-paragraph) (setq epos-font-table epos-default-font-table) (setq epos-paragraph-stylesheet-alist epos-paragraph-stylesheet-defaults) (setq epos-colour-table epos-default-colour-table) (epos-fill-region (point-min) (point-max)) (jit-lock-register 'epos-fontify)) (defun epos-fill-paragraph (&optional ignore) "Fill current paragraph." (let ((paragraph (get-text-property (point) 'epos-paragraph))) (save-excursion ;; If there is no `epos-paragraph' text property at point, then ;; something went wrong. We have to fix it. (or paragraph (setq paragraph (epos-fix-paragraph (point)))) ;; Find start of paragraph, unless we already happen to be at ;; the beginning of it. (unless (or (bobp) (not (eq (get-text-property (1- (point)) 'epos-paragraph) paragraph))) (goto-char (previous-single-property-change (point) 'epos-paragraph (current-buffer) (point-min)))) (save-restriction (narrow-to-region (point) ;; Find end of paragraph. (next-single-property-change (point) 'epos-paragraph (current-buffer) (point-max))) (epos-fill-region-as-paragraph (point-min) (point-max) paragraph))))) (defun epos-paragraph-end-position (&optional pos) (or pos (setq pos (point))) (let ((paragraph (get-text-property pos 'epos-paragraph))) (unless paragraph (epos-fix-paragraph pos)) (next-single-property-change pos 'epos-paragraph (current-buffer) (point-max)))) (defun epos-paragraph-beginning-position (&optional pos) (or pos (setq pos (point))) (let ((paragraph (get-text-property pos 'epos-paragraph))) (unless paragraph (epos-fix-paragraph pos)) (previous-single-property-change pos 'epos-paragraph (current-buffer) (point-min)))) (defun epos-end-of-paragraph (&optional pos) (interactive) (goto-char (epos-paragraph-end-position pos)) (when (and (interactive-p) (get-text-property (1- (point)) 'epos-transient)) (goto-char (previous-single-property-change (point) 'epos-transient (current-buffer) ;; FIXME: (point-min))) (point))) (defun epos-beginning-of-paragraph (&optional pos) (interactive) (goto-char (epos-paragraph-beginning-position pos)) (when (and (interactive-p) (get-text-property (point) 'epos-transient)) (goto-char (next-single-property-change (point) 'epos-transient (current-buffer) ;; FIXME: (point-max))) (point))) (defun epos-fix-paragraph (pos) (or pos (setq pos (point))) (let ((paragraph (get-text-property pos 'epos-paragraph))) (if (epos-paragraph-properties-p paragraph) ;; don't fix if it ain't broken paragraph (let ((begin (previous-single-property-change pos 'epos-paragraph (current-buffer) (point-min))) (end (next-single-property-change pos 'epos-paragraph (current-buffer) (point-max)))) (setq paragraph (get-text-property begin 'epos-paragraph)) (unless paragraph (setq paragraph (make-epos-paragraph-properties))) ; empty (put-text-property begin end 'epos-paragraph paragraph) paragraph)))) (defun epos-resolve-paragraph-properties (paragraph) (let ((styles (list paragraph))) (while (and (epos-paragraph-properties-p paragraph) (epos-paragraph-properties-stylesheet paragraph)) (setq paragraph (epos-paragraph-properties-stylesheet paragraph)) (when (stringp paragraph) (setq paragraph (cdr (assoc paragraph epos-paragraph-stylesheet-alist)))) (when (epos-paragraph-properties-p paragraph) (push paragraph styles))) (epos-merge-paragraph-properties styles))) (defun epos-merge-paragraph-properties (styles) (let ((paragraph-properties (make-epos-paragraph-properties)) (character-properties (make-epos-char-properties))) (dolist (style styles) (epos-nmerge-structs paragraph-properties style) (when (epos-paragraph-properties-character-formatting style) (epos-nmerge-structs character-properties (epos-paragraph-properties-character-formatting style)))) (setf (epos-paragraph-properties-character-formatting paragraph-properties) character-properties) paragraph-properties)) (defun epos-nmerge-structs (to-struct from-struct) (let (val) (dotimes (i (length to-struct)) (setq val (aref from-struct i)) (cond ((eq val 'unset) (aset to-struct i nil)) (val ; non-nil (aset to-struct i val))))) to-struct) (defconst epos-transient-char-properties '(epos-transient t read-only t ;; intangible t )) (defsubst epos-insert-indentation (column) (insert-and-inherit (apply 'propertize ;; `move-to-column' has a bug. It does ;; not work right with the `display' ;; property. So we have to add more than ;; one space. (make-string column ?\ ) 'display `(space :align-to ,column) epos-transient-char-properties))) (defsubst epos-newline () (insert-and-inherit (apply 'propertize "\n" epos-transient-char-properties))) (defun epos-fill-region-as-paragraph (from to paragraph) (save-excursion (save-restriction (narrow-to-region from to) (epos-delete-transient-chars from to) (goto-char (point-min)) ;; FIXME: Numbered and bulleted lists not implemented. Not to ;; mention tables. (let* ((inhibit-read-only t) (properties (epos-resolve-paragraph-properties paragraph)) (left-margin (epos-paragraph-properties-left-indentation properties)) (column (- fill-column (or (epos-paragraph-properties-right-indentation properties) 0))) (first-line (epos-paragraph-properties-first-line-indentation properties))) (when (epos-paragraph-properties-space-before properties) (epos-insert-vspace (epos-paragraph-properties-space-before properties))) (when (or left-margin first-line) (epos-insert-indentation (+ (or left-margin 0) (or first-line 0)))) (move-to-column column) (while (not (eobp)) (cond ((re-search-backward "[ \t]" (line-beginning-position) t) (forward-char 1) (epos-newline) (when left-margin (epos-insert-indentation left-margin))) ((re-search-forward "[ \t]" nil t) (epos-newline) (when left-margin (epos-insert-indentation left-margin))) (t (goto-char (point-max)))) (move-to-column column)) (epos-newline) (when (epos-paragraph-properties-space-after properties) (epos-insert-vspace (epos-paragraph-properties-space-after properties))) (put-text-property (point-min) (point-max) 'epos-paragraph paragraph)))) ;; Stop fill-paragraph from "doing its normal work". t) (defun epos-insert-vspace (height) (insert (apply 'propertize " \n" 'display `(height ,height) epos-transient-char-properties))) (defun epos-delete-transient-chars (from to) (save-excursion (save-restriction (narrow-to-region from to) (goto-char (point-min)) (let ((inhibit-read-only t) beg) (while (setq beg (text-property-any (point-min) (point-max) 'epos-transient t)) (delete-region beg (next-single-property-change beg 'epos-transient (current-buffer) (point-max)))) ;; newline characters are always transient (while (search-forward "\n" nil t) (backward-delete-char 1)))))) (defun epos-fill-region (from to) (save-excursion (save-restriction (narrow-to-region from to) (goto-char (point-min)) (while (not (eobp)) (epos-fill-paragraph) (goto-char (epos-paragraph-end-position)))))) (defsubst epos-resolve-char-props (charprops parprops) ;; FIXME: character formatting stylesheets not implemented. ;; FIXME: some caching would probably be a good idea here. (setq parprops (epos-resolve-paragraph-properties parprops)) (let ((props (make-epos-char-properties))) (when parprops (epos-nmerge-structs props (epos-paragraph-properties-character-formatting parprops))) (when charprops (epos-nmerge-structs props charprops)) (list 'face :inherit (and (epos-char-properties-font props) (aref epos-font-table (epos-char-properties-font props))) :background (if (or (null (epos-char-properties-bg-colour props)) (= (epos-char-properties-bg-colour props) 0)) nil (aref epos-colour-table (epos-char-properties-bg-colour props))) :foreground (if (or (null (epos-char-properties-fg-colour props)) (= (epos-char-properties-fg-colour props) 0)) nil (aref epos-colour-table (epos-char-properties-fg-colour props))) :height (epos-char-properties-height props) ;; FIXME: maybe we should rather implement properties like ;; bold, italic, etc. by merging with according faces? That ;; way users on a tty could specify that they want italic ;; text to be green (or whatever). :weight (and (epos-char-properties-bold props) 'bold) :slant (and (epos-char-properties-italic props) 'italic) :underline (and (epos-char-properties-underlined props) t)))) (defun epos-fontify (start end) (let (to) (while (< start end) (setq to (min (next-single-property-change start 'epos-character (current-buffer) (point-max)) (next-single-property-change start 'epos-paragraph (current-buffer) (point-max)))) (put-text-property start to 'face (epos-resolve-char-props (get-text-property start 'epos-character) (get-text-property start 'epos-paragraph))) (setq start to)))) (defconst example-text ;; We take some example sentences from the GPL. (with-temp-buffer (insert-file-contents (expand-file-name "COPYING" data-directory) nil 323 587) (let ((fill-column 99999)) (fill-region-as-paragraph (point-min) (point-max))) (buffer-string))) (defun wp-set-paragraph-property () (interactive) (let* ((property (completing-read "Property: " '(("left-margin") ("right-margin") ("first-line") ("stylesheet") ("height") ("weight")) nil t)) (paragraph (or (get-text-property (point) 'epos-paragraph) (epos-fix-paragraph (point)))) (charprops (epos-paragraph-properties-character-formatting paragraph))) (unless charprops (setq charprops (make-epos-char-properties)) (setf (epos-paragraph-properties-character-formatting paragraph) charprops)) (cond ((equal property "left-margin") (setf (epos-paragraph-properties-left-indentation paragraph) (string-to-number (read-from-minibuffer "Column: ")))) ((equal property "right-margin") (setf (epos-paragraph-properties-right-indentation paragraph) (string-to-number (read-from-minibuffer "Column: ")))) ((equal property "first-line") (setf (epos-paragraph-properties-first-line-indentation paragraph) (string-to-number (read-from-minibuffer "Amount: ")))) ((equal property "stylesheet") (setf (epos-paragraph-properties-stylesheet paragraph) (completing-read "Stylesheet: " '(("Headline 1") ("Standard")) nil t))) ((equal property "height") (setf (epos-char-properties-height charprops) (let ((height (string-to-number (read-from-minibuffer "Height: ")))) (if (= 0 height) (epos-char-properties-height charprops) height)))) ((equal property "weight") ;; we use that as a toggle. This is just an example. The user ;; interface does not have to be sound. (setf (epos-char-properties-bold charprops) (not (epos-char-properties-bold charprops))))) ;; (let ((inhibit-read-only t)) ;; (put-text-property (epos-paragraph-end-position) ;; (epos-paragraph-beginning-position) ;; 'fontified nil)) (epos-fill-paragraph) ;; (jit-lock-fontify-now) )) (defun wp-example () (interactive) (switch-to-buffer (generate-new-buffer "*tmp*")) (insert (propertize "A headline" 'epos-paragraph (make-epos-paragraph-properties :stylesheet "Headline 1"))) (insert (propertize example-text 'epos-paragraph (make-epos-paragraph-properties :stylesheet "Standard"))) (insert (propertize "Now again, but with margins" 'epos-paragraph (make-epos-paragraph-properties :stylesheet "Headline 1"))) (insert (propertize example-text 'epos-paragraph (make-epos-paragraph-properties :stylesheet "Standard" :first-line-indentation nil :left-indentation 10 :right-indentation 20))) (insert (propertize "Now with character formatting mixed in" 'epos-paragraph (make-epos-paragraph-properties :stylesheet "Headline 1"))) (insert (propertize (concat "Just an example paragraph" (propertize " without " 'epos-character (make-epos-char-properties :italic t)) "any meaning. Let's also add some" (propertize " bold " 'epos-character (make-epos-char-properties :bold t)) "and" (propertize " underlined " 'epos-character (make-epos-char-properties :underlined 'continous)) "text as well as a piece of" (propertize " colour." 'epos-character (make-epos-char-properties :fg-colour 2))) 'epos-paragraph (make-epos-paragraph-properties :stylesheet "Standard" :left-indentation 10))) (epos-mode) (auto-fill-mode -1) (refill-mode -1) (goto-char (point-min))) (defun wp-example-encode () (interactive) (let ((buffer (current-buffer))) (let ((epos-font-table epos-font-table) (epos-colour-table epos-colour-table) (epos-paragraph-stylesheet-alist epos-paragraph-stylesheet-alist)) (with-temp-buffer (insert-buffer buffer) (wp-encode-region (point-min) (point-max)) (with-output-to-temp-buffer "*encoded RTF*" (princ (buffer-substring-no-properties (point-min) (point-max)))))))) (defun wp-encode-region (from to) (save-excursion (save-restriction (narrow-to-region from to) (goto-char (point-min)) ;; (wp-encode-generate-header) (let ((inhibit-read-only t) paragraph) (epos-delete-transient-chars (point-min) (point-max)) (while (not (eobp)) (setq paragraph (or (get-text-property (point) 'epos-paragraph) (epos-fix-paragraph (point)))) (goto-char (wp-encode-paragraph (point) (next-single-property-change (point) 'epos-paragraph (current-buffer) (point-max)) paragraph))) (goto-char (point-min)) (insert "{\\rtf1\\ansi\\deff0") (wp-encode-header) (goto-char (point-max)) (insert "}"))))) (defun wp-find-stylesheet-nr (name) (let ((counter 1)) (catch 'found (dolist (stylesheet epos-paragraph-stylesheet-alist nil) (if (equal name (car stylesheet)) (throw 'found counter) (setq counter (1+ counter))))))) (defun wp-encode-paragraph (from to paragraph) "Encode region FROM TO as PARAGRAPH." (save-restriction (narrow-to-region from to) (goto-char (point-min)) (insert "{\\par\\pard\\plain") (when (epos-paragraph-properties-stylesheet paragraph) (let ((stylesheet-nr (wp-find-stylesheet-nr (epos-paragraph-properties-stylesheet paragraph)))) (when stylesheet-nr (insert (format "\\s%d" stylesheet-nr))))) (insert " ") ;; and so on ... this is very incomplete ... (goto-char (point-max)) (insert "}") (point))) (defun wp-encode-header () ;; I hardcode this. It is just an example. (insert "{\\fonttbl{\\f0\\fswiss Arial;}{\\f1\\froman Times New Roman;}}") (insert "{\\stylesheet{\\s1\\fs48\\f0 Headline 1;}{\\s2\\fs24\\f1 Standard;}}")) --=-=-= Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit Load this file and then type `M-x wp-example RET' you will then see a buffer with some example text. You can type text; you can change some of its properties with `M-x wp-set-paragraph-property'. `M-x wp-example-encode RET' will encode the contents of that WP buffer and show the encoded document in a temp-buffer. Please bear with me. The code has probably a lot of bugs; and the `wp-.*' functions are just quickly hacked together right now. I have abandoned this approach, because the data structure is modelled for RTF alone, which quickly seemed wrong to me. I have been thinking about a more general design since then. But maybe it provides an example for what I have in mind. You have to hit M-q to fill a paragraph -- I have never come to implement something for auto-fill or even refill. M-q calls `epos-fill-paragraph' which in turn calls `epos-fill-region-as-paragraph'. This latter function is the heart of the whitespace formatting. The important data-structure are two defstructs stored in the text properties `epos-character' and `epos-paragraph'. Characters which are inserted by `epos-fill-region-as-paragraph' are marked with a text property `epos-transient', those characters are removed whenever appropriate. You shouldn't hit RET, btw. RET would have to be bound to a function which would create a new paragraph. I also never implemented this. Right now RET would just insert a rogue newline, which will be removed after M-q. [It seems that this thread is becoming infamous as the "thread with the 30 kb mails". I am to blame for that. My apologies. I have been thinking about word processing in Emacs for years, reading specifications, writing prototypes and experiments, acquiring coding skills. Right now I'd like to find out whether I should abandon that project altogether now, because I fear that it won't be welcome because of its fundamental design principles and that it will never be complete.] > b) For a given document, two different applications or the > same application on two different machines/operating > systems might render two different visual representations. > > This is not specifically a problem, and may even give us extra > flexibility. Yes. In fact, I regard it as one of the strengths of word processing. This is where the difference between word processing and "desktop publishing" (DTP) becomes most manifest. Emacs could really excel here by carrying that principle further to media that are not catered for yet by traditional word processors: character consoles. [I didn't meant everything I said to be problematical. I just wanted to make the concepts clear. The term "word processing" is used ambigously in the wild and part of my work in the past has been to draw clear conceptual distinctions.] > This is very important: If a user enters space characters into an > Emacs buffers, she wants there to be space characters. Those > characters would have to become part of the character data in the > encoded file. But if a user just specifies: I want this paragraph to > be indented, then the space characters used to display the left > margin _must_not_ become part of the encoded file. > > Why do you think so? It seems to me that these two different user actions > should both produce spaces in the buffer--in one case, inserted manually, > in the other, caused by the format specification. > > We can recompute line breaks automatically, and represent them by > newline characters in the buffer, which will be removed and replaced > by the next recomputation. In this mode, the user would not manually > enter newline characters except to create breaks (hard newlines). How do you want to solve the problem of distinguishing manually inserted spaces from spaces added programatically for visual rendering when the document is encoded and written to a file? I explained this problem in my last mail with an example RTF. If the user may create indentation both by inserting space characters and by adding a text property via a command, then we have an ambiguity in the user interface, which makes it hazardous. About newlines: I have thought about using hard newlines for paragraph separation. The problem is that I need a place to store properties belonging to the whole paragraph. I have thought about (and experimented with) putting those properties on the final hard newline. But I found it inelegant and there is also some hair in there. The example code identifies as paragraphs every sequence of characters with an `eq' `epos-paragraph' property; the fill function then takes care of the whitespace. I think that this works better. > Erm, what does the concept of "what's really there" in that context > mean? In the buffer, or more generally spoken: in the data structure > a containing block box, or a text property storing formatting > information is, of course, no less there than any space or newline > character added for whitespace formatting. > > Something is "really there" if other Lisp programs will see it in the > way that they are written to look for it. That's what I would regard as "being there" also. But I don't see why this would exclude a box model supported by the display engine (i.e., as you stated more precisely: a box that is rendered at display time). No matter how it happens to be implemented, there would have to be means to check for a box from Lisp and to examine its properties. [This goes actually well beyond the issue at hand: But I'd like to note: we have an open issue here: we have no way to determine the screen column of a buffer position (in canonical character units) from Lisp. This function is a requirement for implementing filling that DTRT with proportional fonts or with fonts that have a different width than the default font. I am by no means competent here, so I may be horribly wrong: but when I looked into it, it seemed to me that this would require help from the display engine and thus short-circuit the boundaries between the display engine and Lisp functions that examine the buffer text. Again: I may be horribly wrong. Nevertheless, with a box model that specifies how to render text at display time, we would have no need for such a function.] Oliver -- Oliver Scholz Jour du Travail de l'Année 212 de la Révolution Ostendstr. 61 Liberté, Egalité, Fraternité! 60314 Frankfurt a. M. --=-=-= Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Disposition: inline _______________________________________________ Emacs-devel mailing list Emacs-devel@gnu.org http://lists.gnu.org/mailman/listinfo/emacs-devel --=-=-=--