Friday, October 24, 2014

#1 2012-12-26 12:39:16 pm

McUsrII
Member
Registered: 2012-11-20
Posts: 2354
Website

A No Frills Text Outliner for TextEdit

Hello.

If you have an outline looking like this:

Code:

# A no frills outlining script for TextEdit

## Hard facts

### Level numbering

### Indentation between Levels

### If you want Left margin or not.

### How many levels you want with linefeeds separating the headings.

## Rationale

### Primary

### Secondary

#### Groff

#### AWK

#### Sed

#### Apple Script

# Using the script

## Syntax

### The levels have to be defined continously deeper.

## Atx style headings - same as in Markdown.

## Laziness

## Ignoring empty lines.

# How it works

## Combining the tools we got.

## The TextEdit script.

## The Awk script

# Installation

## Prerequsites

### TextEdit

### Creating the script bundle

### Saving the Awk script inside it

### Make it all work

#### Choose Save As.

#### Open the package the script bundle consists of in Finder.

#### Navigate to the resources folder

#### Drag the proxy icon over to the Save As dialog in your editor

#### Save the Awk script with the name preProcess.awk

#### Open a terminal window and change the directory to the Resources folder of your script bundle.

#### Perform chmod u+x preProcess.awk in the Terminal Window.

#### Try it on some document with something that can be interpreted as an outline

# Configuration

## Numbering scheme -- lvlNumberScheme

## Left Margin -- removeLeftMargin

## Linefeeds between list items -- lvlWithNewlineSep

## Indentation between levels -- lvlSpacesForIndentation

It will produce an outline like this:

Code:

       I. A no frills outlining script for TextEdit

          1. Hard facts

             A. Level numbering

             B. Indentation between Levels

             C. If you want Left margin or not.

             D. How many levels you want with linefeeds separating the headings.

          2. Rationale

             A. Primary

             B. Secondary
                i. Groff
                ii. AWK
                iii. Sed
                iv. Apple Script

       II. Using the script

          1. Syntax

             A. The levels have to be defined continously deeper.

          2. Atx style headings ‐ same as in Markdown.

          3. Laziness

          4. Ignoring empty lines.

       III. How it works

          1. Combining the tools we got.

          2. The TextEdit script.

          3. The Awk script

       IV. Installation

          1. Prerequsites

             A. TextEdit

             B. Creating the script bundle

             C. Saving the Awk script inside it

             D. Make it all work
                i. Choose Save As.
                ii. Open the package the script bundle consists of in Finder.
                iii. Navigate to the resources folder
                iv. Drag the proxy icon over to the Save As dialog in your editor
                v. Save the Awk script with the name preProcess.awk
                vi. Open a terminal window and change the directory to the Resources folder of your script bundle.
                vii. Perform chmod u+x preProcess.awk in the Terminal Window.
                viii. Try it on some document with something that can be interpreted as an outline

       V. Configuration

          1. Numbering scheme ‐‐ lvlNumberScheme

          2. Left Margin ‐‐ removeLeftMargin

          3. Linefeeds between list items ‐‐ lvlWithNewlineSep

          4. Indentation between levels ‐‐ lvlSpacesForIndentation

I. A no frills outlining script for TextEdit

   1. Hard facts
   
   This script produces a pretty outline in a new TextEdit document, based on a TextEdit document with atx type
   headers in the front document.
   
   The outline may contain a maximum of 6 levels, which should be enough for most cases.
   
   It uses groff (the document processing system every Mac comes with, AWK, and sed to do so.
   
   The script is configurable with regards to:
   
      A. Level numbering
      You can control what kind of numbering scheme you want for each level.

      B. Indentation between levels

      C. If you want Left margin or not.
   
           All this is done by editing properties in the Apple Script, inline instructions.

      D. How  many levels you want with linefeeds separating the headings.
      
      You can adjust this according to your taste, I like it "airy", but if you don't want linefeeds separating your headings
      from a certain level downwards, then there is a property you can set for this. See instructions in the script.

      The outlines that is produced should work well with utf-8 enconded text, that is, if you use special characters, you
      should get correct outpout.

   2. Rationale

      A. Primary
      I have missed a quick and dirty way to produce an outline. The process of creating the outline may be as important
      as the end result, so the foundation for the outline may be the goal. Structure.
      
      This script provides a very easy way to generate good looking outlines, by just editing lines of text and re running the
      script.
      
      It is  should be fun to play with, as you can't really ruin something, and it is also difficult to mess things up, like you may
      be able to do with more complex tools. That removes some barriers for exprimenting with stuff, and freedom is always good.

      B. Secondary
      To show off some tools that comes with every version of Mac Os X, and put their versatility to display.
      
         i. Groff
         groff is the gnu version of troff/nroff, and comes with an abundance of macro packages, for generating manpages, letters,
         articles, books. Think of it as a parallel/ancestor to TeX.
         
         groff comes with many predefined macro packages. See man groff.

         ii. AWK
         Awk is an old tool, a descendant of sed, and it uses the same pattern for its work, that is, pattern action. When no more rules,
         generates a hit for the line, the next line is read and processed.
         
         It is ideal for report generation of various kinds, and perfect for small personal databases. I think I have have proved here,
         that it is also pretty good for making small parsers.
         
         iii. Sed
         Sed is an incredible tool for processing text of all kinds, and gives us Apple Scripters the means for handling most textual
         transformation at the regular expression level.
         
         iv.  AppleScript
         AppleScript sees to that we get stuff in and out of the gui represented by TextEdit in this case.
         
II. Using the script

   1. Syntax

      A. The levels have to be defined continously deeper.
      You can't specify level 4 as the next level after level 2.
         
      You can specify level 2 after level 4. The awk script then finalizes the level 4 and level 3 sublists, and continues on level 2.

   2. Atx style headings ‐ same as in Markdown.
   This is a good thing, when you are finished with your outline, you can reuse its foundation in a markdown document for
   producing html, or whatever.
   The Atx-style syntax is also rather elegant, it is a very fast way to specify a level; by just entering a number #´s in front of
   the line that is to be a heading!
      
   3. Laziness
   If you don't want to, then you don't have to enter more atx headers than necessary. It is really only necessary to change
   the amount of atx headers every time you *change* the outline level.

   4. Ignoring empty lines.
   The script is totally agnostic to empty lines in your foundation for the outline, as it produces its own empty lines,
   it will just ignore yours.

III. How it works

   AppleScript gets text in and out of TextEdit. The atx style outline is then sent throuhg an awk script that inserts
   mm macros for producing an outline with groff.
   The result is then cleaned up for uneccesary linefeeds with sed. 

   1. The TextEdit Apple script
   Contains various properties that can be altered to change the look of the resulting outline. It also runs the whole commandline,
   that calls awk, groff and sed, before making TextEdit create a new document containing the result.

   2. The Awk script
   Is a rather lengthy affaire at 100 lines, I guess I could make it considerably shorter by obfuscating it. By the way, with
   the debugging skeleton in place, it was almost twice as long! It checks the foundation for syntax, and deduces
   what outline level the current header is at.

IV. Installation

   1. Prerequsites

      A. TextEdit
      In order for this to work encoding wise, TextEdit must be configured to read and write utf8. This will also make text
      show up with correct encoding in quicklook.
       
      B. Creating the script bundle
      Compile the AppleScript and save it as a bundle, under your script menu's TextEdit folder with a name like
      TextEditOutline.

      C. Saving the Awk script inside it
      Copy the Awk script into an editor of your choice capable of saving things as utf-8 No Bom. 
      
      D. Make it all work

         i. Choose Save As.

         ii. Open the package the script bundle consists  of
            in Finder.

         iii. Navigate to the resources folder

         iv. Drag  the proxy icon over to the Save As dialog
            in your editor

         v. Save the Awk script with the name preProcess.awk

         vi. Open a terminal window and change the directory
            to the Resources folder of your script bundle.

         vii. Perform   chmod   u+x  preProcess.awk  in  the
            Terminal Window.
            
         viii. Try it on some document with  something  that
            can be interpreted as an outline
           
    If it works then you are all done.

V. Configuration

   There are several properties in the AppleScript that can be used to configure the result of the outlining. The default
   values are stated here, and in the script should you ever need to revert something.

   1. Numbering scheme -- lvlNumberScheme
    The number schem for the outline: You'll need exactly 6 specifiers.
    Below  are the valid specifiers. 
    I : uppercase Roman Numerals i.e I..IX and so on.
    i : lowercase Roman Numerals i.e i..ix and so on.
    1 : arabic numerals i.e 1..9 and so on
    A : uppercase letters.
    a : lowercase letters.
    Edit to suit your taste! : Original value: "I1Ai1a"
   
   2. Left Margin -- removeLeftMargin
   Boolean set this to true or false for whether you want the left margin consisting of 7 spaces removed or not. 
   Edit to suit your taste! Original value : true.

   3. Linefeeds between list items -- lvlWithNewlineSep
   This property has to be text, and it has to be from 1 to 6 in value.
   The number of levels ,specify the levels that will embellish lower
   levels with linefeeds. Make it lesser than 6 to compact your outline.
   Edit to suit your taste!    Original value : "6"
   
   
   4. Indentation between levels -- lvlSpacesForIndentation
   This property has to be text, and it has to be a number denoting the number 
   of spaces for indentation.
   Edit to your taste! Original value : "3"

The AppleScript that should be saved as a bundle with the name TextEditOutline in your TextEdit Scripts folder.

Applescript:


# TextEditOutline
# © McUsr 2012 And put into public domain under the license GPL 1.0
# I interpret GPL 1.0 as that you may not post it, have it in a script collection for public consumption, or a repository for a
# closed circle, or charge something by using this, or a development of this work into something of your own.
# Nor charge for a compilation of scripts or tips where this script is included. Sharing between friends are fine!
# Please refer to this link otherwise: http://macscripter.net/viewtopic.php?pid=159019#p159019
# Release 1.0.2
# There are no guarantees about anything what_so_ever.
script TextEditOutline
   property parent : AppleScript
   property lvlNumberScheme : "I1Ai1a"
   # The number schem for the outline: You'll need exactly 6 specifiers.
   # These are the valid specifiers. : original string: "I1Ai1a"
   # I : uppercase Roman Numerals i.e I..IX and so on.
   # i : lowercase Roman Numerals i.e i..ix and so on.
   # 1 : arabic numerals i.e 1..9 and so on
   # A : uppercase letters.
   # a : lowercase letters.
   # Edit to suit your taste!
   
   property lvlWithNewlineSep : "6"
   # this property has to be text, and it has to be from 1 to 6 in value
   # the number of levels here will specify the levels, that will embellish lower
   # levels with new line. Make it lesser to compact your outline.
   # Edit to your taste!    
   
   property lvlSpacesForIndentation : "3"
   # this property has to be text, and it has to be a number denoting the number of spaces for indentation.
   # Edit to your taste!
   
   property removeLeftMargin : true
   # boolean set this to true or false for whether you want the left margin consisting of 7 spaces removed or not
   on run
       global theText
       # We get the text out of the text edit document.
       local rpath, failed
       set rpath to POSIX path of (path to resource "preProcess.awk")
       # The path to the awkscript in our bundler.
       
       set failed to false
       tell application "TextEdit"
           try
               set theText to text of its document 1
           on error
               set failed to true
           end try
       end tell
       if not failed then
           local tids, theItems
           set {tids, AppleScript's text item delimiters} to {AppleScript's text item delimiters, return}
           set theItems to every text item of theText
           set AppleScript's text item delimiters to linefeed
           set theText to theItems as text
           set AppleScript's text item delimiters to tids
           tell application "TextEdit"
               tell its document 1
                   local a, b
                   set text of it to theText
                   try
                       # we only save if the document has a path
                       set a to path of it
                       set b to a
                       save
                   end try
               end tell
           end tell
           # We update the document with the returns sifted out.
           # This is for when we update the outline, by a document.
           # we'll then remove any returns obtained through the clipboard.
           if removeLeftMargin = true then
               set imRes to (do shell script rpath & " -v outlineNumbering=\"" & lvlNumberScheme & "\" -v linefeedsForLevels=\"" & lvlWithNewlineSep & "\" -v indentSpaces=\"" & lvlSpacesForIndentation & "\" <<<" & quoted form of theText & " |preconv -e utf8 |groff -dpaper=a1 -s -mm -Tutf8 |sed -e 1d -e :a -e '/^\\n*$/N;/\\n$/ba' |sed -e 's/^[ ]\\{7\\}//g' " without altering line endings)
           else
               set imRes to (do shell script rpath & " -v outlineNumbering=\"" & lvlNumberScheme & "\" -v linefeedsForLevels=\"" & lvlWithNewlineSep & "\" -v indentSpaces=\"" & lvlSpacesForIndentation & "\" <<<" & quoted form of theText & " |preconv -e utf8 |groff -dpaper=a1 -s -mm -Tutf8 |sed -e 1d -e :a -e '/^\\n*$/N;/\\n$/ba' " without altering line endings)
           end if
           tell application "TextEdit"
               make new document at front
               tell its document 1
                   set text of it to imRes
               end tell
               activate
           end tell
       end if
   end run
end script
tell TextEditOutline to run

This is the awk script that must be put into the Resources folder of the script
bundle. You also have to make it executable with chmod u+x from a Terminal window.

Code:

#!/usr/bin/awk -f
# © McUsr 2012 And put into public domain under the license GPL 1.0
# I interpret GPL 1.0 as that you may not post it, have it in a script collection for public consumption, or a repository for a
# closed circle, or charge something by using this, or a development of this work into something of your own.
# Nor charge for a compilation of scripts or tips where this script is included. Sharing between friends are fine!
# Please refer to this link otherwise: http://macscripter.net/viewtopic.php?pid=159019#p159019
# Release 1.0.0
BEGIN { curLevel=0 ; haderror = 0 ; initialized=0; }
function perror() {
# will work in filename.
printf("preProcess.awk: Missing levels ...\nBailing out!\n")
haderror=1
exit 1
}
function initSeq() {
# the linelength, set large, to avoid indenting.
print ".ll 30i" ;
# organizing of "Paper size and such"
print ".PGNH"
# no headers
print ".nr Ls " linefeedsForLevels
# embed newlines around list-elms all 6 levels.
# change this to contract newlines between blocks with a level.
print ".nr Li " indentSpaces
# indent a deeper level with 3 spaces.
print ".nr PO 0i"
}
function startList( listLevel ) {
printf(".AL %s\n", substr(outlineNumbering,listLevel,1))
}
$0 ~ /^#\ / {

if (curLevel == 0) {
if ( initialized == 0 ) {
initSeq() ; initialized=1 ;
}
curLevel=1 ; startList(curLevel) ;
} else if ( curLevel > 1 ) {
while ( --curLevel > 1)
print ".LE" ;
print ".LE" ;
}
}
$0 ~ /^##\ / {
if (curLevel == 1) {
curLevel=2 ; startList(curLevel) ;
} else if ( curLevel > 2 ) {
while ( --curLevel > 2 )
print ".LE" ;
print ".LE" ;
} else if ( curLevel < 1 )
perror() ;
}
$0 ~ /^###\ / {
if (curLevel == 2 ) {

curLevel=3 ; startList(curLevel) ;
} else if ( curLevel > 3 ) {
while ( --curLevel > 3 )
print ".LE" ;
print ".LE" ;
} else if ( curLevel < 2 )
perror() ;
}
$0 ~ /^####\ / {
if (curLevel == 3) {
curLevel=4 ; startList(curLevel) ;
} else if ( curLevel > 4 ) {
while ( --curLevel > 4 )
print ".LE" ;
print ".LE" ;
} else if ( curLevel < 3 )
perror() ;
}
$0 ~ /^#####\ / {
if (curLevel == 4) {
curLevel=5 ; startList(curLevel) ;
} else if ( curLevel > 5 ) {
print ".LE" ; curLevel=5 ;
} else if ( curLevel < 4 )
perror() ;
}
$0 ~ /^######\ / {
if (curLevel == 5) {
curLevel=6 ; startList(curLevel) ;
} else if ( curLevel != 6 )
perror() ;
}
$0 !~ /^##*/ {
if ( $0 !~ /^[ \t]*$/ ) {
if ( level == 0 && initialized == 0 ) {
initSeq() ; initialized=1 ; curLevel=1 ; startList(curLevel)
}
}
}
{
if ( $0 !~ /^[ \t]*$/ ) { print ".LI" ; sub("^##*\ ","") ; sub("^[ \t][ \t]*","") ; print $0 ; next }
}
END {
if ( haderror == 0 ) {

if ( curLevel > 0 ) {
while ( --curLevel > 0 )
print ".LE" ;
} else { print "Nothing to do." }
}
}

Enjoy smile

Last edited by McUsrII (2012-12-27 12:02:20 pm)


Filed under: awk, TextEdit, groff, Outlining

Offline

 

#2 2012-12-27 09:59:25 am

McUsrII
Member
Registered: 2012-11-20
Posts: 2354
Website

Re: A No Frills Text Outliner for TextEdit

You can downloade a premade and assembled script bundle from  here. You should really open it and compile it before using it, especially if you are on Mountain Lion.

This is release 1.0.2 I have changed the script so it will only save the document, if the document was already saved, after having replaced returns with linefeeds. I have also set the levels separated with linefeeds back to 6.

I have also updated the script in post #1

Last edited by McUsrII (2012-12-27 10:02:09 am)


Filed under: awk, TextEdit, outline, groff

Offline

 

#3 2013-01-01 11:18:59 am

McUsrII
Member
Registered: 2012-11-20
Posts: 2354
Website

Re: A No Frills Text Outliner for TextEdit

Happy new year!

I am having a very bad internet connection at the moment. So I'll come back later and maybe clean this up.

Here is the pre-processing step  for the script above, it takes a Markdown document, and conveverts any settex headers back to atx. The outline script works best with atx headers. It is somewhat robust, as it ignores any settex headings at the very start of the document, and settex headings (lines with === or —) under an empty line. If the settex heading is superfluos, with an atx header aside of the heading, then we'll just use that one.

Here it is, it should be assembled with the same parts, using the very same procedure  as for the awk script above, with just a name change. settexToAtx.sed is the name of it.

I guess it could be easier to implement this script using words, text item delimiters and paragraphs within AppleScript, but I am not totally sure, that's why I settled for sed. What those two approaches has in common, is of course a portable way to implement such routines among a slew of TextEditors. smile

Code:

#!/usr/bin/sed -nf
# Tries to be robust, we figure out if there is a === or --- line where it shouldn't
# that is starting the file, or with an empty line above it. Or that there is an
# atx header above the line with the setex heading, then we keep this one.
# A line is read into patternSpace
# bug: CAN'T catch a settex header coming after an atx header of wrong kind.
: s
/^[ ]*[ ]*$/ {
n
}
/^[=][=]*/ {
g
# gets back the line from hold space, overwriting the current
/^\n$/ b s
# for the case that === is on a line alone.
# branches to top, thinks this works without getting next line
# because we have emptied holdspace.
/^$/ b s
# for the case that === is the first line in the file
/^#\{1\}/ {
p
# so we found even an atx header above, we'll spit out this one.
n
# gets a new line of input
h
# stores it onto the holdspace
n
# gets a new line of input into the pattern space
b s
# branches to start.
}
s/^/# /p
# we prepend the heading with a # to convert the setex1 to an atx1 heading
n
}
/^[-][-]*/ {
g
# see comment in simili above.
/^\n$/ b s
/^$/ b s
/^#\{2\}/ {
p
n
h
n
b s
}
s/^/## /p
n
}
# special case, an atx header in the last line.
$ {
/^#\{1,6\}/ p
b
# branches to end, q would be as good.
}
# none of above, we'll get the old contents of holdspace and check it.
x
# switches holdspace an pattern space to process in correct order
/^#\{1,6\}/ {
# So we have found a genuine atx heading.
p
# we print it out.
n
# new line of input into pattern space (correct order).
b s
}

Last edited by McUsrII (2013-01-04 10:29:06 am)


Filed under: sed, TextEdit, markdown

Offline

 

#4 2013-01-04 10:30:37 am

McUsrII
Member
Registered: 2012-11-20
Posts: 2354
Website

Re: A No Frills Text Outliner for TextEdit

Hello.

I have made the sed script above more robust/removed some bugs. smile


Filed under: sed, markdown, Atx, Setex

Offline

 

Board footer

Powered by FluxBB

[ Generated in 0.050 seconds, 12 queries executed ]

RSS (new topics) RSS (active topics)