all messages for Emacs-related lists mirrored at yhetil.org
 help / color / mirror / code / Atom feed
From: Nicolas Goaziou <n.goaziou@gmail.com>
To: Bastien <bzg@gnu.org>
Cc: emacs-orgmode <emacs-orgmode@gnu.org>
Subject: Re: wish: provide flush_right/right_aligned text rendering directive
Date: Thu, 22 May 2014 00:12:57 +0200	[thread overview]
Message-ID: <877g5ezspi.fsf@gmail.com> (raw)
In-Reply-To: <87k39fje7m.fsf@bzg.ath.cx> (Bastien's message of "Wed, 21 May 2014 18:20:29 +0200")

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

Bastien <bzg@gnu.org> writes:

> Yes -- I suggest we simply put this aside for the moment.

Well, actually it required more work than I thought. Here is the patch,
with some documentation. I didn't test it thoroughly, so feedback is
welcome.


Regards,

-- 
Nicolas Goaziou

[-- Attachment #2: 0001-ox-ascii-Implement-justifyright-and-justifyleft-bloc.patch --]
[-- Type: text/x-diff, Size: 17369 bytes --]

From 744ee75b33ce1dea299626621558901d9ada09ef Mon Sep 17 00:00:00 2001
From: Nicolas Goaziou <n.goaziou@gmail.com>
Date: Wed, 21 May 2014 23:37:00 +0200
Subject: [PATCH] ox-ascii: Implement "justifyright" and "justifyleft" blocks

* lisp/ox-ascii.el
(org-ascii--justify-lines): New function.  Renamed from
`org-ascii--justify-string'.
(org-ascii--justify-element, org-ascii--current-justification): New
functions.
(org-ascii-verse-block, org-ascii-table-cell, org-ascii-table
  org-ascii-src-block, org-ascii-property-drawer, org-ascii-planning,
  org-ascii-paragraph, org-ascii-paragraph,
  org-ascii-latex-environment, org-ascii-horizontal-rule,
  org-ascii-fixed-width, org-ascii-export-block,
  org-ascii-example-block, org-ascii-clock, org-ascii-center-block,
  org-ascii-template--document-title,
  org-ascii-template--document-title): Use new functions.

* doc/org.texi (ASCII/Latin-1/UTF-8 export): Document new feature.

This patches also fixes centering of tables.
---
 doc/org.texi     |  19 +++++
 lisp/ox-ascii.el | 227 +++++++++++++++++++++++++++++++++++--------------------
 2 files changed, 165 insertions(+), 81 deletions(-)

diff --git a/doc/org.texi b/doc/org.texi
index c685748..9cf0d7f 100644
--- a/doc/org.texi
+++ b/doc/org.texi
@@ -10804,6 +10804,25 @@ specified using an @code{ATTR_ASCII} line, directly preceding the rule.
 -----
 @end example
 
+@subheading ASCII special blocks
+@cindex special blocks, in ASCII export
+@cindex #+BEGIN_JUSTIFYLEFT
+@cindex #+BEGIN_JUSTIFYRIGHT
+
+In addition to @code{#+BEGIN_CENTER} blocks (@pxref{Paragraphs}), it is
+possible to justify contents to the left or the right of the page with the
+following dedicated blocks.
+
+@example
+#+BEGIN_JUSTIFYLEFT
+It's just a jump to the left
+#+END_JUSTIFYLEFT
+
+#+BEGIN_JUSTIFYRIGHT
+And then a step to the right.
+#+END_JUSTIFYRIGHT
+@end example
+
 @node Beamer export
 @section Beamer export
 @cindex Beamer export
diff --git a/lisp/ox-ascii.el b/lisp/ox-ascii.el
index 858e3f0..b7ed268 100644
--- a/lisp/ox-ascii.el
+++ b/lisp/ox-ascii.el
@@ -385,14 +385,14 @@ nil to ignore the inline task."
 
 ;; Internal functions fall into three categories.
 
-;; The first one is about text formatting.  The core function is
-;; `org-ascii--current-text-width', which determines the current
-;; text width allowed to a given element.  In other words, it helps
-;; keeping each line width within maximum text width defined in
-;; `org-ascii-text-width'.  Once this information is known,
-;; `org-ascii--fill-string', `org-ascii--justify-string',
-;; `org-ascii--box-string' and `org-ascii--indent-string' can
-;; operate on a given output string.
+;; The first one is about text formatting.  The core functions are
+;; `org-ascii--current-text-width' and
+;; `org-ascii--current-justification', which determine, respectively,
+;; the current text width allowed to a given element and its expected
+;; justification.  Once this information is known,
+;; `org-ascii--fill-string', `org-ascii--justify-lines',
+;; `org-ascii--justify-element' `org-ascii--box-string' and
+;; `org-ascii--indent-string' can operate on a given output string.
 
 ;; The second category contains functions handling elements listings,
 ;; triggered by "#+TOC:" keyword.  As such, `org-ascii--build-toc'
@@ -421,7 +421,8 @@ a communication channel.
 Optional argument JUSTIFY can specify any type of justification
 among `left', `center', `right' or `full'.  A nil value is
 equivalent to `left'.  For a justification that doesn't also fill
-string, see `org-ascii--justify-string'.
+string, see `org-ascii--justify-lines' and
+`org-ascii--justify-block'.
 
 Return nil if S isn't a string."
   ;; Don't fill paragraph when break should be preserved.
@@ -436,8 +437,8 @@ Return nil if S isn't a string."
 		 (fill-region (point-min) (point-max) justify))
 	       (buffer-string))))))
 
-(defun org-ascii--justify-string (s text-width how)
-  "Justify string S.
+(defun org-ascii--justify-lines (s text-width how)
+  "Justify all lines in string S.
 TEXT-WIDTH is an integer specifying maximum length of a line.
 HOW determines the type of justification: it can be `left',
 `right', `full' or `center'."
@@ -453,6 +454,40 @@ HOW determines the type of justification: it can be `left',
 	(forward-line)))
     (buffer-string)))
 
+(defun org-ascii--justify-element (contents element info)
+  "Justify CONTENTS of ELEMENT, as a block.
+INFO is a plist used as a communication channel.  Justification
+is done according to the widest non blank line in CONTENTS.  It
+is appropriate for regular (i.e, non-greater) elements, except
+paragraphs, which should be filled instead."
+  (if (not (org-string-nw-p contents)) contents
+    (let ((text-width (org-ascii--current-text-width element info))
+	  (how (org-ascii--current-justification element)))
+      (if (eq how 'left) contents
+	;; Paragraphs are treated specially as they also need to be
+	;; filled.
+	(if (eq (org-element-type element) 'paragraph)
+	    (org-ascii--fill-string contents text-width info how)
+	  (with-temp-buffer
+	    (insert contents)
+	    (goto-char (point-min))
+	    (let ((max-width 0))
+	      ;; Compute max width.
+	      (save-excursion
+		(while (not (eobp))
+		  (unless (org-looking-at-p "[ \t]*$")
+		    (end-of-line)
+		    (when (> (current-column) max-width)
+		      (setq max-width (current-column))))
+		  (forward-line)))
+	      ;; Justify every line according to TEXT-WIDTH and MAX-WIDTH.
+	      (while (not (eobp))
+		(unless (org-looking-at-p "[ \t]*$")
+		  (org-indent-to-column
+		   (/ (- text-width max-width) (if (eq how 'right) 1 2))))
+		(forward-line)))
+	    (buffer-string)))))))
+
 (defun org-ascii--indent-string (s width)
   "Indent string S by WIDTH white spaces.
 Empty lines are not indented."
@@ -539,6 +574,21 @@ INFO is a plist used as a communication channel."
 		       (or (org-list-get-tag beg-item struct)
 			   (org-list-get-bullet beg-item struct)))))))))))))
 
+(defun org-ascii--current-justification (element)
+  "Return expected justification for ELEMENT's contents.
+Return value is a symbol among `left', `center', `right' and
+`full'."
+  (let (justification)
+    (while (and (not justification)
+		(setq element (org-element-property :parent element)))
+      (case (org-element-type element)
+	(center-block (setq justification 'center))
+	(special-block
+	 (let ((name (org-element-property :type element)))
+	   (cond ((string= name "JUSTIFYRIGHT") (setq justification 'right))
+		 ((string= name "JUSTIFYLEFT") (setq justification 'left)))))))
+    (or justification 'left)))
+
 (defun org-ascii--build-title
   (element info text-width &optional underline notags toc)
   "Format ELEMENT title and return it.
@@ -879,7 +929,7 @@ INFO is a plist used as a communication channel."
 	   date "\n\n\n"))
 	 ((org-string-nw-p date)
 	  (concat
-	   (org-ascii--justify-string date text-width 'right)
+	   (org-ascii--justify-lines date text-width 'right)
 	   "\n\n\n"))
 	 ((and (org-string-nw-p author) (org-string-nw-p email))
 	  (concat author "\n" email "\n\n\n"))
@@ -900,7 +950,7 @@ INFO is a plist used as a communication channel."
 			    (string-width (or email "")))
 		       2)
 		    text-width) (if utf8p ?━ ?_))))
-	(org-ascii--justify-string
+	(org-ascii--justify-lines
 	 (concat line "\n"
 		 (unless utf8p "\n")
 		 (upcase formatted-title)
@@ -1021,8 +1071,7 @@ contextual information."
   "Transcode a CENTER-BLOCK element from Org to ASCII.
 CONTENTS holds the contents of the block.  INFO is a plist
 holding contextual information."
-  (org-ascii--justify-string
-   contents (org-ascii--current-text-width center-block info) 'center))
+  contents)
 
 
 ;;;; Clock
@@ -1031,16 +1080,18 @@ holding contextual information."
   "Transcode a CLOCK object from Org to ASCII.
 CONTENTS is nil.  INFO is a plist holding contextual
 information."
-  (concat org-clock-string " "
-	  (org-translate-time
-	   (org-element-property :raw-value
-				 (org-element-property :value clock)))
-	  (let ((time (org-element-property :duration clock)))
-	    (and time
-		 (concat " => "
-			 (apply 'format
-				"%2s:%02s"
-				(org-split-string time ":")))))))
+  (org-ascii--justify-element
+   (concat org-clock-string " "
+	   (org-translate-time
+	    (org-element-property :raw-value
+				  (org-element-property :value clock)))
+	   (let ((time (org-element-property :duration clock)))
+	     (and time
+		  (concat " => "
+			  (apply 'format
+				 "%2s:%02s"
+				 (org-split-string time ":"))))))
+   clock info))
 
 
 ;;;; Code
@@ -1088,8 +1139,10 @@ contextual information."
 (defun org-ascii-example-block (example-block contents info)
   "Transcode a EXAMPLE-BLOCK element from Org to ASCII.
 CONTENTS is nil.  INFO is a plist holding contextual information."
-  (org-ascii--box-string
-   (org-export-format-code-default example-block info) info))
+  (org-ascii--justify-element
+   (org-ascii--box-string
+    (org-export-format-code-default example-block info) info)
+   example-block info))
 
 
 ;;;; Export Snippet
@@ -1107,7 +1160,8 @@ CONTENTS is nil.  INFO is a plist holding contextual information."
   "Transcode a EXPORT-BLOCK element from Org to ASCII.
 CONTENTS is nil.  INFO is a plist holding contextual information."
   (when (string= (org-element-property :type export-block) "ASCII")
-    (org-remove-indentation (org-element-property :value export-block))))
+    (org-ascii--justify-element
+     (org-element-property :value export-block) export-block info)))
 
 
 ;;;; Fixed Width
@@ -1115,9 +1169,11 @@ CONTENTS is nil.  INFO is a plist holding contextual information."
 (defun org-ascii-fixed-width (fixed-width contents info)
   "Transcode a FIXED-WIDTH element from Org to ASCII.
 CONTENTS is nil.  INFO is a plist holding contextual information."
-  (org-ascii--box-string
-   (org-remove-indentation
-    (org-element-property :value fixed-width)) info))
+  (org-ascii--justify-element
+   (org-ascii--box-string
+    (org-remove-indentation
+     (org-element-property :value fixed-width)) info)
+   fixed-width info))
 
 
 ;;;; Footnote Definition
@@ -1193,7 +1249,7 @@ information."
   (let ((text-width (org-ascii--current-text-width horizontal-rule info))
 	(spec-width
 	 (org-export-read-attribute :attr_ascii horizontal-rule :width)))
-    (org-ascii--justify-string
+    (org-ascii--justify-lines
      (make-string (if (and spec-width (string-match "^[0-9]+$" spec-width))
 		      (string-to-number spec-width)
 		    text-width)
@@ -1358,7 +1414,9 @@ information."
 CONTENTS is nil.  INFO is a plist holding contextual
 information."
   (when (plist-get info :with-latex)
-    (org-remove-indentation (org-element-property :value latex-environment))))
+    (org-ascii--justify-element
+     (org-remove-indentation (org-element-property :value latex-environment))
+     latex-environment info)))
 
 
 ;;;; Latex Fragment
@@ -1433,7 +1491,7 @@ information."
   "Transcode a PARAGRAPH element from Org to ASCII.
 CONTENTS is the contents of the paragraph, as a string.  INFO is
 the plist used as a communication channel."
-  (org-ascii--fill-string
+  (org-ascii--justify-element
    (if (not (wholenump org-ascii-indented-line-width)) contents
      (concat
       ;; Do not indent first paragraph in a section.
@@ -1442,7 +1500,7 @@ the plist used as a communication channel."
 		       'section))
 	(make-string org-ascii-indented-line-width ?\s))
       (replace-regexp-in-string "\\`[ \t]+" "" contents)))
-   (org-ascii--current-text-width paragraph info) info))
+   paragraph info))
 
 
 ;;;; Plain List
@@ -1479,25 +1537,27 @@ INFO is a plist used as a communication channel."
   "Transcode a PLANNING element from Org to ASCII.
 CONTENTS is nil.  INFO is a plist used as a communication
 channel."
-  (mapconcat
-   'identity
-   (delq nil
-	 (list (let ((closed (org-element-property :closed planning)))
-		 (when closed
-		   (concat org-closed-string " "
-			   (org-translate-time
-			    (org-element-property :raw-value closed)))))
-	       (let ((deadline (org-element-property :deadline planning)))
-		 (when deadline
-		   (concat org-deadline-string " "
-			   (org-translate-time
-			    (org-element-property :raw-value deadline)))))
-	       (let ((scheduled (org-element-property :scheduled planning)))
-		 (when scheduled
-		   (concat org-scheduled-string " "
-			   (org-translate-time
-			    (org-element-property :raw-value scheduled)))))))
-   " "))
+  (org-ascii--justify-element
+   (mapconcat
+    #'identity
+    (delq nil
+	  (list (let ((closed (org-element-property :closed planning)))
+		  (when closed
+		    (concat org-closed-string " "
+			    (org-translate-time
+			     (org-element-property :raw-value closed)))))
+		(let ((deadline (org-element-property :deadline planning)))
+		  (when deadline
+		    (concat org-deadline-string " "
+			    (org-translate-time
+			     (org-element-property :raw-value deadline)))))
+		(let ((scheduled (org-element-property :scheduled planning)))
+		  (when scheduled
+		    (concat org-scheduled-string " "
+			    (org-translate-time
+			     (org-element-property :raw-value scheduled)))))))
+    " ")
+   planning info))
 
 
 ;;;; Property Drawer
@@ -1506,7 +1566,8 @@ channel."
   "Transcode a PROPERTY-DRAWER element from Org to ASCII.
 CONTENTS holds the contents of the drawer.  INFO is a plist
 holding contextual information."
-  (org-string-nw-p contents))
+  (and (org-string-nw-p contents)
+       (org-ascii--justify-element contents property-drawer info)))
 
 
 ;;;; Quote Block
@@ -1567,11 +1628,13 @@ contextual information."
   (let ((caption (org-ascii--build-caption src-block info))
 	(code (org-export-format-code-default src-block info)))
     (if (equal code "") ""
-      (concat
-       (when (and caption org-ascii-caption-above) (concat caption "\n"))
-       (org-ascii--box-string code info)
-       (when (and caption (not org-ascii-caption-above))
-	 (concat "\n" caption))))))
+      (org-ascii--justify-element
+       (concat
+	(when (and caption org-ascii-caption-above) (concat caption "\n"))
+	(org-ascii--box-string code info)
+	(when (and caption (not org-ascii-caption-above))
+	  (concat "\n" caption)))
+       src-block info))))
 
 
 ;;;; Statistics Cookie
@@ -1620,25 +1683,27 @@ holding contextual information."
 CONTENTS is the contents of the table.  INFO is a plist holding
 contextual information."
   (let ((caption (org-ascii--build-caption table info)))
-    (concat
-     ;; Possibly add a caption string above.
-     (when (and caption org-ascii-caption-above) (concat caption "\n"))
-     ;; Insert table.  Note: "table.el" tables are left unmodified.
-     (cond ((eq (org-element-property :type table) 'org) contents)
-	   ((and org-ascii-table-use-ascii-art
-		 (eq (plist-get info :ascii-charset) 'utf-8)
-		 (require 'ascii-art-to-unicode nil t))
-	    (with-temp-buffer
-	      (insert (org-remove-indentation
-		       (org-element-property :value table)))
-	      (goto-char (point-min))
-	      (aa2u)
-	      (goto-char (point-max))
-	      (skip-chars-backward " \r\t\n")
-	      (buffer-substring (point-min) (point))))
-	   (t (org-remove-indentation (org-element-property :value table))))
-     ;; Possible add a caption string below.
-     (and (not org-ascii-caption-above) caption))))
+    (org-ascii--justify-element
+     (concat
+      ;; Possibly add a caption string above.
+      (when (and caption org-ascii-caption-above) (concat caption "\n"))
+      ;; Insert table.  Note: "table.el" tables are left unmodified.
+      (cond ((eq (org-element-property :type table) 'org) contents)
+	    ((and org-ascii-table-use-ascii-art
+		  (eq (plist-get info :ascii-charset) 'utf-8)
+		  (require 'ascii-art-to-unicode nil t))
+	     (with-temp-buffer
+	       (insert (org-remove-indentation
+			(org-element-property :value table)))
+	       (goto-char (point-min))
+	       (aa2u)
+	       (goto-char (point-max))
+	       (skip-chars-backward " \r\t\n")
+	       (buffer-substring (point-min) (point))))
+	    (t (org-remove-indentation (org-element-property :value table))))
+      ;; Possible add a caption string below.
+      (and (not org-ascii-caption-above) caption))
+     table info)))
 
 
 ;;;; Table Cell
@@ -1701,7 +1766,7 @@ a communication channel."
     (let* ((indent-tabs-mode nil)
 	   (data
 	    (when contents
-	      (org-ascii--justify-string
+	      (org-ascii--justify-lines
 	       contents width
 	       (org-export-table-cell-alignment table-cell info)))))
       (setq contents
@@ -1800,7 +1865,7 @@ CONTENTS is verse block contents.  INFO is a plist holding
 contextual information."
   (let ((verse-width (org-ascii--current-text-width verse-block info)))
     (org-ascii--indent-string
-     (org-ascii--justify-string contents verse-width 'left)
+     (org-ascii--justify-element contents verse-block info)
      org-ascii-quote-margin)))
 
 
-- 
1.9.3


  reply	other threads:[~2014-05-21 22:12 UTC|newest]

Thread overview: 21+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-05-10 13:52 wish: provide flush_right/right_aligned text rendering directive Gregor Zattler
2014-05-21  2:30 ` Bastien
2014-05-21  7:39   ` Gregor Zattler
2014-05-21 11:48     ` Bastien
2014-05-21 13:06       ` Nicolas Goaziou
2014-05-21 13:13         ` Bastien
2014-05-21 13:36           ` Nicolas Goaziou
2014-05-21 13:49             ` Bastien
2014-05-21 14:34               ` Nicolas Goaziou
2014-05-21 15:51                 ` Bastien
2014-05-21 16:12                   ` Nicolas Goaziou
2014-05-21 16:20                     ` Bastien
2014-05-21 22:12                       ` Nicolas Goaziou [this message]
2014-05-22  8:38                         ` Bastien
2014-05-22 11:51                           ` Nicolas Goaziou
2014-05-22 12:30                             ` Bastien
2014-05-22  9:03                         ` Sebastien Vauban
2014-05-22  9:15                           ` Bastien
2014-05-22  9:26                             ` Sebastien Vauban
2014-05-22 11:27                           ` Nicolas Goaziou
2014-05-23 20:54                         ` thanks, works great (was: Re: wish: provide flush_right/right_aligned text rendering directive) Gregor Zattler

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

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

  git send-email \
    --in-reply-to=877g5ezspi.fsf@gmail.com \
    --to=n.goaziou@gmail.com \
    --cc=bzg@gnu.org \
    --cc=emacs-orgmode@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 external index

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

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.