Archive for July, 2006

Omnioutliner to BBCode conversion – my PHP script

Thursday, July 13th, 2006

The following is adapted from an email I sent to the OmniOutliner-users mailing list. I should also add that after fighting with this stupid WP editor, I’m having a very hard time convincing it that I really want to display ‘raw’ html instead of it helpfully converting it right back to entities for me. I also understand that the code is probably very hard to read, so if you’re interested in checking it out, I would recommend that you download the attached file, convert; hopefully that will make much more sense.
In my email, I asked:

Is there an SDK for developing OmniOutliner export plugins? If so, or if not, would there be sufficient interest in creating a BBCode export option from OmniOutliner? Just throwing it out there.

I ask, because I was asked to post some notes I took in OmniOutliner Pro… on a web discussion forum where they use BBCode instead of regular HTML to format stuff.

Embedded lists in BBCode look like this:

[list]Item 1
[list]Item 1a
Item 1b[/list]
Item 2
Item 3
[list]Item 3a
Item 3b[/list]
Item 4

The above would produce this output:

  • Item 1
  • Item 1a
  • Item 1b
  • Item 2
  • Item 3
    • Item 3a
    • Item 3b
  • Item 4
  • Fairly simple and straightforward, but I was kind of racking my brain as to how to get my OmniOutliner document into this format. So I wrote this PHP script, called ‘convert.’ In my example below, I copied this script into my Documents -> planning folder, where I’m keeping the rest of my files.

    ---------------------------------convert----------------------
    #!/usr/bin/php
    
    // Take first command line argument as the filename
    $fa = file($_SERVER["argv"][1]);
    
    $prevtabs = 0;
    
    $ent_table = array("-" => "−", " " => " ", "+" => "√");
    
    // test it out first
    //for ($i=0; $i < 10; $i++)
    
    for ($i=0; $i< count($fa); $i++)
    {
      $match_array = array();
    
      $itworked = preg_match("#^([\t]{0,})(- \[[+\- ]\] )(.*)$#", $fa[$i], $match_array);
    
      if ($itworked)
      {
        $curtabs = strlen($match_array[1]);
    
        $thediff = $curtabs - $prevtabs;
    
        if ($thediff > 0) // means we indented inwards.
        {
          if ($i > 0) // not on the very first line
          {
            print "&#8711; " . $prev_line;
          }
          print str_repeat("[list]", $thediff);
        }
        else if ($thediff < 0)
        {
          if ($i > 0) // not on the very first line
          {
            print "&#8226; " . $prev_line;
          }
          print str_repeat("[/list]", $thediff * -1);
        }
        else // same, no change
        {
          if ($i > 0) // not on the very first line
          {
            print "&#8226; " . $prev_line;
          }      
        }
        // set this as the previous line amount now
        $prevtabs = $curtabs;
    
        $prev_line = "[" . $ent_table[$match_array[2][3]]. "] " . $match_array[3] . "\n";
      }
      else
      {
        // The match failed, so err on the side of caution and print the previous line with a bullet,
        // then set the new previous line to be the whole line we couldn't match
        if ($i > 0) // not on the very first line
        {
          print "&#8226; " . $prev_line;
        }
        $prev_line = $fa[$i];
        // $prevtabs // not gonna change it, hope it stays the same. ack.
      }
    }
    // last line has no children, by definition, so:
    print "&#8226; " . $prev_line;
    
    if ($prevtabs > 0)
    {
      print str_repeat("[/list]", $prevtabs);
    }
    ?>
    -------------------------------------------------------------------

    Usage:

    Export your OmniOutliner document as tab-separated values (a .tsv file. Except OmniOutliner’s export insists on making it end in .txt. Ugh. Can we please get a ‘Hide file extension’ checkbox to uncheck, and then override the default?)

    In the Terminal, change directories to the folder containing this script, and your TSV file.

    unixprompt> cd ~/Documents/planning

    I called my exported file, planning_notes.txt
    And I want my output file called, ‘output.txt’:

    unixprompt> ./convert planning_notes.txt > output.txt
    If it doesn’t work – remember to make the script executable first:

    unixprompt> chmod 755 convert

    If you don’t redirect the output into a file, it will just print right in the terminal
    window, which may be preferred:

    unixprompt> ./convert planning_notes.txt

    [b]∇ [ ] Intro[/b]
    [list][b]∇ [ ] Who are we[/b]
    [list][b]• [ ] and what are our goals while we’re here?[/b]
    [/list]∇ [ ] Thom
    [list]• [ ] Tech Team Director
    • [ ] How can tech team help?
    [/list]
    [/list]
    etc.

    * * *

    Some notes about the code and formatting -

    I chose to use the • entity, whose code is • for all of the ‘leaf’ items, and I decided to use the ∇ (∇) entity, the downward pointing triangle, to represent ‘branches’ (rows with children).

    I did this by not printing each line immediately; instead I saved it until the next time through the loop, where I could see whether the next line indented further. Based on this, I knew whether to make it a bullet or an open ‘disclosure triangle.’ ;)

    After either the triangle or bullet, I kept the square brackets containing either a space (unchecked), a ‘minus’ entity (−) or a “√” (which is √), for a ‘checked off’ item. The conversion table is near the top, in the $ent_table array.

    Note that I commented out a ‘first ten lines only’ version of my for-loop — I’d used that earlier so I could test and see if it would work, before turning it loose on my whole document!

    One frustrating thing was, choosing to start from the tab separated values format didn’t give me any style information. So I still ended up going through my document once it had been exported and converted, and [b]re-bolding[/b] certain lines after the fact. This is obviously not the most ideal solution, but it’s a solution. (I made a custom BBEdit Glossary folder called ‘BBCode’ with a ‘bold’ file in it, simply containing [b]#select#[/b] and I assigned that to a key. Then I selected each line I wanted to bold and hit my hotkey.)

    I started out with a much simpler version of this script, but then I fell victim to ‘feature creep’ and I kept making it better… and now I’m really happy with the results.

    Anyway, hope this script is of use to someone out there.

    Keep your swap offa my free disk space!

    Sunday, July 9th, 2006

    OS X took a big step forward from OS 9 when it did away with zero-sum memory requirements. It used to be the case that if you had 96 MB of RAM, then the sum of the memory your programs used couldn’t exceed that 96 MB. Sure, there was ‘virtual memory’, but the anecdotal advice was, “Just set it 1 MB larger than your installed memory.” The reason for this: it reduced the amount of physical memory each program needed in order to run, without bogging the machine down too much. Swap was pretty slow.

    So now we’re in a day and age where it’s pretty regular to have at least 512 MB of physical memory, it’s regular to see 1 GB or more, and power users can have in excess of… well, anywhere from 4 GB to 16 GB for their computation- or data- hungry processes. And swap, of course, happens automatically. You can just open as many applications as your little heart desires, and the OS will intelligently move bits around for you. No more ‘Get Info’ to tweak the amount a program can use. You can have tons of browser windows (and now tabs) open at the same time. (Firefox is a huge memory hog, and can get a bit bogged down, but at least it’s now possible to do this.)

    My gripe comes in where the famous adage leaves off, “Nature abhorrs a vacuum.” It seems that no matter how big my notebook’s hard drive is, I always manage to fill it. And whenever I come within about 1 GB of filling the drive, my machine begins to churn. Coincidence? I think not; there is exactly 1 GB of physical ram installed in my machine.

    Now, I understand that Apple is all about brain-dead simplicity. To ask their users to grok the concept of, “swap” is simply too much. And yet, don’t you think those same users are going to find it a little odd that their hard drive space is mysteriously disappearing as they keep opening more browser windows and tabs? Sure, you could blame apps that have memory leaks; I’m sure that’s a contributing factor. But I wish I had a simple, easy way to set up a machine from the get-go with a bona fide partition which would be, simply, for SWAP. No more mysterious disappearing free disk space. The machine would crawl a lot less. When you were out of drive space, you got rid of files – right now, I can do a reboot and free up, on average, 1.4 GB of space right there.

    The next time I set up a personal OS X machine, I may create a small 2 GB partition and try to figure out how to specify that it be used explicitly for swap. That small step would go a long way towards reducing a lot of frustrated waiting and rebooting down the road – time that certainly adds up – and just force me to clean house once in a while instead of putting it off and rebooting.

    Google is my friend:

    • http://www.math.columbia.edu/~bayer/OSX/swapfile/
    • http://www.bombich.com/mactips/swap.html
    • http://www.macosxhints.com/article.php?story=20040716153639236
    • http://wiki.onmac.net/index.php/Triple_Boot_via_BootCamp

    Some of these links are clearly out of date but it’s interesting to see what Double- and Triple- booting have added, complexity-wise, to this problem.