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[/code]

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[/code]

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.
  1. 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.


# 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." }
}

}[/code]
Enjoy :slight_smile:

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

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. :slight_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

}[/code]

Hello.

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