TaskPaper to Omnifocus, need a tweak $

Hello Hello,

My name is George and I’m just getting into applescript(translatation I know very little). For productivity I use Omnifocus 2 and TaskPaper and I found an that trigger’s a script over at github https://github.com/RobTrew/tree-tools/tree/7e96d5748388dd870606ebba1e636654e2fb47a3/OmniFocus%20scripts/TaskPaper%20scripts which basically imports TaskPaper projects and tasks into Omnifocus just like that Project is a Project in Omnifocus and the Project Tasks are the Project Task in Omnifocus but the scrip is creating another top level item in the task like.

Below is how it looks in Taskpaper so Test is the Project name and the items preceded by the dash are the task

When I run the script I get these this pop ups alerting of what’s going to up

So far so good but when I go to Omnifocus to see the result of the import it looks like so:

Notice how the “one” is a sub project of Test and then task are all under “one” So basically the script is indenting the 1st task and I’m trying to figure how to amend the script so it doesn’t do this and it treats all the task as task. Any help or guidance would extremely appreciated. I would also consider some monetary remuneration ($20) for a fix as well - payment via paypal.

Thanks
George

property pTitle : "Text from file or clipboard to OF"
property pVer : "0.51"
property pBanner : pTitle & "  Ver. " & pVer

property pClipImport : "Import this text into OF"
property plstExtensions : {"txt", "taskpaper"}

property plstLines : {}
property plstLevelParents : {}

-- FUNCTION	Imports Taskpaper formatted text as OmniFocus projects and (indented) actions
-- USAGE:
--			EITHER	1. Copy text into the clipboard and run this script
--			OR		2. Select one or more .txt or .taskpaper files in Finder, Copy [Cmd C], and run this script
--			OR		3. Drag one or more .txt or .taskpaper files onto the icon of this script

--			NOTE:	I use it in a KeyBoard Maestro Action which precedes it with a Copy action.
--					This allows me to select some text in an editor, (or some files in a Finder window),
--					and send things straight into OF with one keystroke.

-- CHANGE LOG

-- ver .51		Corrected handling of multiple files dropped on the droplet
-- ver .52		Corrects handling of selected text

on run
	-- Read the clipboard contents
	try
		set strLines to ((the clipboard) as text)
	on error
		tell application id "com.apple.systemevents"
			activate
			display dialog "No text in the clipboard" buttons {"OK"} with title pBanner
		end tell
		return
	end try
	
	-- and the Finder selection
	tell application id "com.apple.finder"
		set lstSeln to selection as list
		if length of lstSeln > 1 then
			set strFinderSeln to ""
			set blnFirst to true
			repeat with i from 1 to length of (lstSeln)
				if blnFirst then
					set blnFirst to false
				else
					set strFinderSeln to strFinderSeln & return
				end if
				set strFinderSeln to strFinderSeln & name of item i of lstSeln
			end repeat
		else
			set strFinderSeln to ""
		end if
	end tell
	
	-- IF the text in the clipboard is the return delimited list of names of files selected in Finder
	-- Then get the lines from all of the selected files that have the right extension
	if strLines = strFinderSeln then
		-- IMPORT CONTENTS OF ANY TEXT FILES
		set strLines to ""
		tell application id "com.apple.finder"
			repeat with i from 1 to length of lstSeln
				set strFileName to (item i of lstSeln) as string
				set blnOK to my CheckExtension(strFileName, plstExtensions)
				set refFile to (a reference to (file strFileName))
				if blnOK then set strLines to strLines & my ReadTextFile(refFile)
			end repeat
		end tell
		
		ImportLines(strLines, strFinderSeln)
	else
		-- OFFER TO IMPORT THE TEXT
		tell application id "com.apple.systemevents"
			activate
			set varResponse to display dialog strLines buttons {"Esc", pClipImport} default button pClipImport cancel button "Esc" with title pBanner
			if varResponse is false then return
		end tell
		
		ImportLines(strLines, "the Clipboard:")
	end if
	
	set plstLines to {}
	set plstLevelParents to {}
end run

on open lstFiles
	
	set strLines to ""
	set blnOK to true
	tell application id "com.apple.finder"
		repeat with i from 1 to length of lstFiles
			set strFileName to (item i of lstFiles) as string
			
			set blnOK to my CheckExtension(strFileName, plstExtensions)
			if blnOK then
				set refFile to (a reference to (file strFileName))
				set strLines to strLines & my ReadTextFile(refFile)
			else
				exit repeat
			end if
			
		end repeat
	end tell
	
	if blnOK then
		ImportLines(strLines, lstFiles as text)
	else
		tell application id "com.apple.systemevents"
			activate
			display dialog "Expects one of following file extensions: " & return & return & my ExtensionList() buttons {"OK"} with title pBanner
		end tell
	end if
	
	set plstLines to {}
	set plstLevelParents to {}
end open

on ExtensionList()
	set text item delimiters to " ."
	set strList to "." & plstExtensions as text
	set text item delimiters to space
	strList
end ExtensionList

on CheckExtension(strFileName, lstExtensions)
	set text item delimiters to "."
	set lstParts to text items of strFileName
	
	set lngParts to length of lstParts
	if lngParts < 2 then
		return false
	else
		ignoring case
			set strSuffix to (item lngParts of lstParts)
			return (lstExtensions contains strSuffix)
		end ignoring
	end if
end CheckExtension

on ImportLines(strLines, strSource)
	tell application "OmniFocus"
		set oDoc to default document
		tell oDoc
			if number of document window is 0 then
				make new document window with properties {bounds:{0, 0, 1000, 500}}
			end if
			
			set fldrImport to make new folder with properties {name:"Taskpaper Import " & (current date)}
		end tell
	end tell
	
	
	set recStats to TP_OF(strLines, oDoc, fldrImport)
	
	
	set strMsg to (("Imported from:" & return & return & strSource & return & return & "	Inbox tasks:		" & (Inbox of recStats) as string) & return ¬
		& "	Projects:			" & (Projects of recStats) as string) & return ¬
		& "	Project tasks:	" & (Tasks of recStats) as string
	
	tell application id "com.apple.systemevents"
		activate
		display dialog strMsg buttons {"OK"} with title pBanner
	end tell
end ImportLines


on GetImportFolder(oDoc, fldrImport)
	try
		set m to fldrImport
	on error
		tell oDoc
			set fldrImport to make new folder with properties {name:"Taskpaper Import " & (current date)}
		end tell
	end try
	return fldrImport
end GetImportFolder


on ReadTextFile(theFile)
	open for access theFile
	try
		set fileContents to (read theFile)
	on error
		set fileContents to ""
	end try
	close access theFile
	return fileContents
end ReadTextFile

on TP_OF(strLines, oDoc, fldrImport)
	set lngInbox to 0
	set lngProjects to 0
	set lngTasks to 0
	
	set plstLines to paragraphs of strLines
	
	tell application "OmniFocus"
		
		tell oDoc
			set will autosave to false
		end tell
		-- Read the file line by line
		
		-- Establish current destinations for:
		---- NOTES (promoted to tasks in 
		---- TASKS
		-- (Before a PROJECT has been encountered, we assume that 
		--  the default destination is the inbox)
		
		set oTaskParent to oDoc
		set oNoteParent to missing value
		
		set plstLevelParents to {}
		
		ignoring case
			repeat with strLine in plstLines
				-- trim off leading and trailing space characters (not tabs)
				set strLine to my Trim(strLine)
				-- Count any leading TABS and extract remaining line
				set {lngLevel, strLine} to my ParseLevel(strLine)
				
				
				-- skip empty lines
				set lngChars to length of strLine
				if lngChars > 0 then
					
					-- distinguish between tasks, notes, and project headers
					if first character of strLine ≠ "-" then
						
						if last character of strLine ≠ ":" then
							-- NOTE
							if oNoteParent ≠ missing value then
								-- append this text to current note
								set note of oNoteParent to note of oNoteParent & strLine & return
								
							else -- "Note" at start of doc - interpret as inbox task
								tell oDoc to parse tasks into with transport text strLine without as single task
								set lngInbox to lngInbox + 1
							end if
							
						else -- HEADER: NEW PROJECT
							if lngChars > 1 then
								set strProjectName to text 1 thru -2 of strLine
								
								-- Distinguish between normal projects and
								-- instances of "Inbox:"
								if strProjectName ≠ "Inbox" then
									-- PROJECT: 
									tell fldrImport
										set oProject to make new project with properties {name:strProjectName}
										set lngProjects to lngProjects + 1
										set oNoteParent to oProject
										set oTaskParent to oProject
										-- Specify this as the parent of any Level 1 tasks which follow
										set plstLevelParents to {oProject}
										-- Record how many tabs precede the project header
										
									end tell
								else -- INBOX:
									set oTaskParent to oDoc
									-- Notes can not be attached to the Inbox
									-- We will treat any note lines as Inbox Tasks
									set oNoteParent to missing value
								end if
							end if
						end if
					else -- First character is "-"
						if lngChars > 1 then
							if second character of strLine ≠ " " then
								-- NOTE
								set note of oNoteParent to note of oNoteParent & strLine & return
							else -- TASK
								-- drop the leading "- "
								set strLine to text 3 thru -1 of strLine
								set lngParents to length of plstLevelParents
								
								-- Parse any tags into a record of properties
								set recProps to my ParseTask(oDoc, strLine)
								
								set cParent to class of oTaskParent
								if cParent ≠ document then
									-- and identify its parent (correcting any over-indentation)
									
									if lngLevel > lngParents then
										set lngLevel to lngParents
									end if
									set oTaskParent to item lngLevel of plstLevelParents
									tell oTaskParent
										set oTask to make new task with properties recProps
										set lngTasks to lngTasks + 1
									end tell
									
								else -- cParent is document
									tell oTaskParent
										set oTask to make new inbox task with properties recProps
										set lngInbox to lngInbox + 1
									end tell
								end if
								
								
								-- Record this task as the parent of any note which follows
								set oNoteParent to oTask
								
								-- Record this task as the parent of any tasks at the next level of indentation
								set lngNextLevel to lngLevel + 1
								if lngNextLevel > lngParents then
									set end of plstLevelParents to oTask
								else
									set item lngNextLevel of plstLevelParents to oTask
								end if
							end if
						end if
					end if
				end if
			end repeat
		end ignoring
		
		tell oDoc
			set will autosave to true
		end tell
	end tell
	
	return {Inbox:lngInbox, Projects:lngProjects, Tasks:lngTasks}
	
end TP_OF



on Trim(someText)
	local someText
	
	repeat until someText does not start with " "
		if (length of someText) > 1 then
			set someText to text 2 thru -1 of someText
		else
			set someText to ""
		end if
	end repeat
	
	repeat until someText does not end with " "
		if length of someText > 1 then
			set someText to text 1 thru -2 of someText
		else
			set someText to ""
		end if
	end repeat
	
	return someText
end Trim

on RTrim(someText)
	local someText
	
	repeat until someText does not end with return
		if length of someText > 1 then
			set someText to text 1 thru -2 of someText
		else
			set someText to ""
		end if
	end repeat
	
	return someText
end RTrim

on ParseLevel(strLine)
	set lngLevel to 1 --Assume project headings and inboxes are zero
	repeat while strLine starts with tab
		set lngLevel to lngLevel + 1
		
		if length of strLine > 1 then
			set strLine to text 2 thru -1 of strLine
		else
			set strLine to ""
			exit repeat
		end if
	end repeat
	
	return {lngLevel, strLine}
end ParseLevel

on ParseTask(oDoc, strTask)
	-- Return recTask as property list for an Omnifocus Task
	set recTask to {}
	if length of strTask > 0 then
		set strOldDelims to text item delimiters
		
		set text item delimiters to " @"
		set lstParts to text items of strTask
		
		set recTask to {name:(item 1 of lstParts) as string} & recTask
		
		set lngParts to count of lstParts
		set blnContextSet to false
		if lngParts > 1 then
			
			set text item delimiters to "("
			ignoring case
				using terms from application "OmniFocus"
					repeat with strPart in rest of lstParts
						set lstTagVal to text items of strPart
						set strTag to item 1 of lstTagVal
						if (count of lstTagVal) > 1 then
							set strVal to text 1 thru -2 of (item 2 of lstTagVal)
						else
							set strVal to ""
						end if
						if length of strTag > 0 then
							if strTag ≠ "done" then
								if strTag ≠ "start" then
									if strTag ≠ "due" then
										if strTag ≠ "mins" then
											if (strTag ≠ "flag") then
												if blnContextSet then
													--Skip any additional context
												else
													set oCat to my GetContext(oDoc, strTag)
													if oCat ≠ missing value then
														set recTask to {context:oCat} & recTask
													end if
												end if
											else -- flagged
												-- set flag of recTask to true
												set recTask to {flagged:true} & recTask
											end if
										else -- mins
											try
												set lngMins to strVal as integer
												-- set mins of recTask to strVal
												
												set recTask to {estimated minutes:lngMins} & recTask
												
											end try
										end if
									else -- due
										-- set due of recTask to strVal
										set dteDue to my ParseDate(strVal)
										if dteDue ≠ 0 then
											set recTask to {due date:dteDue} & recTask
										end if
									end if
								else -- start()
									set dteStart to my ParseDate(strVal)
									if dteStart ≠ 0 then
										set recTask to {defer date:dteStart} & recTask
									end if
								end if
							else -- done
								-- set zapped of recTask to true
								set recTask to {completed:true} & recTask
							end if
						end if
					end repeat
				end using terms from
			end ignoring
			
		else -- very short
			set recTask to {name:strTask}
		end if
		
		set text item delimiters to strOldDelims
	end if
	return recTask
end ParseTask

on GetContext(oDoc, strTag)
	using terms from application "OmniFocus"
		set strSum to strTag as string
		tell oDoc
			set oContexts to complete strTag as context maximum matches 1
			if length of oContexts > 0 then
				set oContext to context id (id of item 1 of oContexts)
			else --
				set oContext to make new context with properties {name:strTag}
			end if
		end tell
	end using terms from
	return oContext
end GetContext

on ParseDate(strDate)
	try
		set dte to date strDate
		set blnDate to true
	on error
		set strOldDelims to text item delimiters
		set text item delimiters to " "
		
		--try
		set lstDateTime to text items of strDate
		
		set blnDate to true
		try
			set strDate to item 1 of lstDateTime
			set text item delimiters to "-"
			set lstDateParts to text items of strDate
			set lngYear to item 1 of lstDateParts as integer
			set lngMonth to item 2 of lstDateParts as integer
			set lngDay to item 3 of lstDateParts as integer
		on error
			set blnDate to false
		end try
		
		set blnTime to true
		try
			set strTime to item 2 of lstDateTime
			set text item delimiters to ":"
			set lstTimeParts to text items of strTime
			set lngHours to item 1 of lstTimeParts as integer
			set lngMins to item 2 of lstTimeParts as integer
		on error
			set blnTime to false
		end try
		
		if blnDate then
			set dte to current date
			set hours of dte to 0
			set minutes of dte to 0
			set seconds of dte to 0
			
			set year of dte to lngYear
			set day of dte to 1 -- (All months have 1st, some lack 29-31)
			set month of dte to lngMonth
			set day of dte to lngDay -- (and now the day we want)
			
			if blnTime then
				if lngHours > 0 or lngMinutes > 0 then
					set hours of dte to lngHours
					set minutes of dte to lngMins
				end if
				
			end if
			
		end if
		
		set text item delimiters to strOldDelims
	end try
	
	if blnDate then
		return dte
	else
		return 0
	end if
end ParseDate

Hello.

I haven’t got Ofocus2, but it seems to me, that you are obtaining a reference to a variable, and then changing its content, could you please try to comment out this:

          -- Record this task as the parent of any note which follows
                               set oNoteParent to oTask

And then try the script, without importing any notes.

Ok thanks let me try it.

Hello.

Hopefully that should work all right. If it does, then there are only some small adjustments that must be made. :slight_smile:

I just tried it and I’m afraid its not changing anything, its still doing the same thing :frowning: thanks though

Maybe, I’m not doing it right, by commenting out do you mean to copy the suggest script change. I clicked the Open this Scriplet in your Editor: and replaced it with the one in the script.

Hello.

There is a line in your script like this

set oNoteParent to oTask

please change that line into

# set oNoteParent to oTask

It does have the comment

-- Record this task as the parent of any note which follows

above it.

You can quickly search for oNoteParent, by selecting one of the occurrences, and hit cmd-E, then cmd-G until you are on the right one.

When that line is commented out, you have re-compiled the script, and saved it, and is ready to give it a spin, then you should import only a project with tasks, and no notes. This is to see if my suspicions are right, that it is a problem concerning a reference. If my suspicions are right, the project should have the tasks below it, at the same level.

Thanks.

I tried and it looks like the above shot and saved it. I then recompiled it and the same result.

Hello.

I must say your screenshot was most enlightening!

Please change the lines below the one you changed from

  -- Record this task as the parent of any tasks at the next level of indentation
                               set lngNextLevel to lngLevel + 1
                               if lngNextLevel > lngParents then
                                   set end of plstLevelParents to oTask
                               else
                                   set item lngNextLevel of plstLevelParents to oTask
                               end if

into

(*
  -- Record this task as the parent of any tasks at the next level of indentation
                               set lngNextLevel to lngLevel + 1
                               if lngNextLevel > lngParents then
                                   set end of plstLevelParents to oTask
                               else
                                   set item lngNextLevel of plstLevelParents to oTask
                               end if
*)

Now it ought to work, as long as you haven’t got any tasks under tasks, or notes under the tasks, that should all be on the first level under the project.

I hope you can verify that! :slight_smile:

Hello.

As far as I can see, you have some problems with the logic in your on TP_OF(strLines, oDoc, fldrImport) handler.

the problem is the way you set the lngParents contra the way you set the lngNextLevel variable. The first time around, the lngNextLevel variable is greater than lngParents, and the element is inserted as it should.

the next time around, then lngParents is 2, and then lngNextLevel is also 2, so the next task, is taken for a subtask, of the previous.

I think it should be possible to find a way around this, but tweaking the logic slightly, for instance insert a greater than or equal to, instead of greater than where you test lngNextLevel against lngParents. But I haven’t thought that through at this moment.

I do think that you can remove all the comments for now, and I’ll come back to you in the morning with some suggestions. :slight_smile:

Thank you sir, I’ll try commenting out that strip and see what happens.

Cheers,
G

McUsrII, that worked like a charm now it just creates the Project (top level) and the task (children). I’ll send you a PM

Thanks,
George

Hello.

I meant that you should remove the comments, for commenting out the code, as I am sure the culprit is a misalignment, of the variables you use to keep track of the nextLevel, and the current level, and the parent.

I have to test what I think of, but I will post a suggestion early in the morning. :slight_smile:

Have a good evening.

Thanks again, I’ll check back in the morning.

Tasks below tasks, or notes below tasks won’t work at this time, but I guess, the basis functionality is good for starters.

To go further with this, you really should rewrite your code with good semantic names. The main problem here, was that you have tried, and tried well to manipulate a tree structure with a linear solution, that just won’t work.

Having said that, I think you have done a great job, making it work so far. :slight_smile:

I am not sure if I have the time to help you with making it work for all situations, but for this to be more than a big ball of mud, I really need you to rewrite your code with proper variable names.

Study my changes carefully, and know that they are just intermediary fixes, to give you the basic functionality. All changes should have been marked properly. You should keep a copy of your original code safe, so that you can compare.

You can donate what you think this tweak was worth to MacScripters. :wink:

property pTitle : "Text from file or clipboard to OF"
property pVer : "0.52 - BUGFIX"
property pBanner : pTitle & " Ver. " & pVer

property pClipImport : "Import this text into OF"
property plstExtensions : {"txt", "taskpaper"}

property plstLines : {}
property plstLevelParents : {}

-- FUNCTION    Imports Taskpaper formatted text as OmniFocus projects and (indented) actions
-- USAGE:
--            EITHER    1. Copy text into the clipboard and run this script
--            OR        2. Select one or more .txt or .taskpaper files in Finder, Copy [Cmd C], and run this script
--            OR        3. Drag one or more .txt or .taskpaper files onto the icon of this script

--            NOTE:    I use it in a KeyBoard Maestro Action which precedes it with a Copy action.
--                    This allows me to select some text in an editor, (or some files in a Finder window),
--                    and send things straight into OF with one keystroke.

-- CHANGE LOG

-- ver .51        Corrected handling of multiple files dropped on the droplet
-- ver .52        Corrects handling of selected text

on run
	-- Read the clipboard contents
	try
		set strLines to ((the clipboard) as text)
	on error
		tell application id "com.apple.systemevents"
			activate
			display dialog "No text in the clipboard" buttons {"OK"} with title pBanner
		end tell
		return
	end try
	
	-- and the Finder selection
	tell application id "com.apple.finder"
		set lstSeln to selection as list
		if length of lstSeln > 1 then
			set strFinderSeln to ""
			set blnFirst to true
			repeat with i from 1 to length of (lstSeln)
				if blnFirst then
					set blnFirst to false
				else
					set strFinderSeln to strFinderSeln & return
				end if
				set strFinderSeln to strFinderSeln & name of item i of lstSeln
			end repeat
		else
			set strFinderSeln to ""
		end if
	end tell
	
	-- IF the text in the clipboard is the return delimited list of names of files selected in Finder
	-- Then get the lines from all of the selected files that have the right extension
	if strLines = strFinderSeln then
		-- IMPORT CONTENTS OF ANY TEXT FILES
		set strLines to ""
		tell application id "com.apple.finder"
			repeat with i from 1 to length of lstSeln
				set strFileName to (item i of lstSeln) as string
				set blnOK to my CheckExtension(strFileName, plstExtensions)
				set refFile to (a reference to (file strFileName))
				if blnOK then set strLines to strLines & my ReadTextFile(refFile)
			end repeat
		end tell
		
		ImportLines(strLines, strFinderSeln)
	else
		-- OFFER TO IMPORT THE TEXT
		tell application id "com.apple.systemevents"
			activate
			set varResponse to display dialog strLines buttons {"Esc", pClipImport} default button pClipImport cancel button "Esc" with title pBanner
			if varResponse is false then return
		end tell
		
		ImportLines(strLines, "the Clipboard:")
	end if
	
	set plstLines to {}
	set plstLevelParents to {}
end run

on open lstFiles
	
	set strLines to ""
	set blnOK to true
	tell application id "com.apple.finder"
		repeat with i from 1 to length of lstFiles
			set strFileName to (item i of lstFiles) as string
			
			set blnOK to my CheckExtension(strFileName, plstExtensions)
			if blnOK then
				set refFile to (a reference to (file strFileName))
				set strLines to strLines & my ReadTextFile(refFile)
			else
				exit repeat
			end if
			
		end repeat
	end tell
	
	if blnOK then
		ImportLines(strLines, lstFiles as text)
	else
		tell application id "com.apple.systemevents"
			activate
			display dialog "Expects one of following file extensions: " & return & return & my ExtensionList() buttons {"OK"} with title pBanner
		end tell
	end if
	
	set plstLines to {}
	set plstLevelParents to {}
end open

on ExtensionList()
	set text item delimiters to " ."
	set strList to "." & plstExtensions as text
	set text item delimiters to space
	strList
end ExtensionList

on CheckExtension(strFileName, lstExtensions)
	set text item delimiters to "."
	set lstParts to text items of strFileName
	
	set lngParts to length of lstParts
	if lngParts < 2 then
		return false
	else
		ignoring case
			set strSuffix to (item lngParts of lstParts)
			return (lstExtensions contains strSuffix)
		end ignoring
	end if
end CheckExtension

on ImportLines(strLines, strSource)
	global oDoc
	tell application "OmniFocus"
		set oDoc to default document
		tell oDoc
			if number of document window is 0 then
				make new document window with properties {bounds:{0, 0, 1000, 500}}
			end if
			
			set fldrImport to make new folder with properties {name:"Taskpaper Import " & (current date)}
		end tell
	end tell
	
	
	set recStats to TP_OF(strLines, oDoc, fldrImport)
	
	
	set strMsg to (("Imported from:" & return & return & strSource & return & return & "    Inbox tasks:        " & (Inbox of recStats) as string) & return ¬
		& "    Projects:            " & (Projects of recStats) as string) & return ¬
		& "    Project tasks:    " & (Tasks of recStats) as string
	
	tell application id "com.apple.systemevents"
		activate
		display dialog strMsg buttons {"OK"} with title pBanner
	end tell
end ImportLines


on GetImportFolder(oDoc, fldrImport)
	try
		set m to fldrImport
	on error
		tell oDoc
			set fldrImport to make new folder with properties {name:"Taskpaper Import " & (current date)}
		end tell
	end try
	return fldrImport
end GetImportFolder


on ReadTextFile(theFile)
	open for access theFile
	try
		set fileContents to (read theFile)
	on error
		set fileContents to ""
	end try
	close access theFile
	return fileContents
end ReadTextFile

on TP_OF(strLines, oDoc, fldrImport)
	set lngInbox to 0
	set lngProjects to 0
	set lngTasks to 0
	
	set plstLines to paragraphs of strLines
	
	tell application "OmniFocus"
		
		tell oDoc
			set will autosave to false
		end tell
		-- Read the file line by line
		
		-- Establish current destinations for:
		---- NOTES (promoted to tasks in 
		---- TASKS
		-- (Before a PROJECT has been encountered, we assume that 
		-- the default destination is the inbox)
		
		set oTaskParent to oDoc
		set oNoteParent to missing value
		
		set plstLevelParents to {}
		
		ignoring case
			repeat with strLine in plstLines
				-- trim off leading and trailing space characters (not tabs)
				set strLine to my Trim(strLine)
				-- Count any leading TABS and extract remaining line
				set {lngLevel, strLine} to my ParseLevel(strLine)
				
				
				-- skip empty lines
				set lngChars to length of strLine
				if lngChars > 0 then
					
					-- distinguish between tasks, notes, and project headers
					if first character of strLine ≠ "-" then
						
						if last character of strLine ≠ ":" then
							-- NOTE
							if oNoteParent ≠ missing value then
								-- append this text to current note
								set note of oNoteParent to note of oNoteParent & strLine & return
								
							else -- "Note" at start of doc - interpret as inbox task
                               tell oDoc to parse tasks into with transport text strLine without as single task
								set lngInbox to lngInbox + 1
							end if
							
						else -- HEADER: NEW PROJECT
							if lngChars > 1 then
								set strProjectName to rich text 1 thru -2 of strLine
								
								-- Distinguish between normal projects and
								-- instances of "Inbox:"
								if strProjectName ≠ "Inbox" then
									-- PROJECT: 
									tell fldrImport
										set oProject to make new project with properties {name:strProjectName}
										set lngProjects to lngProjects + 1
										set oNoteParent to oProject
										set oTaskParent to oProject
										-- Specify this as the parent of any Level 1 tasks which follow
										set plstLevelParents to {oProject}
										-- Record how many tabs precede the project header
										-- #CHANGE# MOVED:
										set lngParents to 1
										set childLevel to 2
										set oldLevel to 2
										-- END #CHANGE#
									end tell
								else -- INBOX:
									set oTaskParent to oDoc
									-- Notes can not be attached to the Inbox
									-- We will treat any note lines as Inbox Tasks
									set oNoteParent to missing value
								end if
							end if
						end if
					else -- First character is "-"
						if lngChars > 1 then
							if second character of strLine ≠ " " then
								-- NOTE
								set note of oNoteParent to note of oNoteParent & strLine & return
							else -- TASK
								-- drop the leading "- "
								set strLine to rich text 3 thru -1 of strLine
								-- #CHANGE# REMOVED:
								-- set lngParents to length of plstLevelParents
								-- END #CHANGE#
								
								-- Parse any tags into a record of properties
								set recProps to my ParseTask(oDoc, strLine)
								
								set cParent to class of oTaskParent
								if cParent ≠ document then
									-- and identify its parent (correcting any over-indentation)
									-- #CHANGE# REMOVED:
									(*
									if lngLevel > lngParents then
										set lngLevel to lngParents
									end if
									*)
									if lngLevel > childLevel then
										-- pushing a stack comes here!
										set lngParents to length of plstLevelParents
										set childLevel to childLevel + 1
										-- it can't be different, because we can only indent one level at a time!
									end if
									-- #CHANGE# ADDED:
									
									-- #CHANGE
									--  set oTaskParent to item lngLevel of plstLevelParents
									set oTaskParent to item lngParents of plstLevelParents
									-- END "CHANGE"
									
									tell oTaskParent
										set oTask to make new task with properties recProps
										set lngTasks to lngTasks + 1
									end tell
									
								else -- cParent is document
									tell oTaskParent
										set oTask to make new inbox task with properties recProps
										set lngInbox to lngInbox + 1
									end tell
								end if
								
								
								-- Record this task as the parent of any note which follows
								set oNoteParent to oTask
								
								-- Record this task as the parent of any tasks at the next level of indentation
								-- 	set lngNextLevel to lngLevel + 1
								# CHANGED
								if oldLevel = childLevel then
									set end of plstLevelParents to oTask
								else
									set item -1 of plstLevelParents to oTask
								end if
								# END OF CHANGE
							end if
						end if
					end if
				end if
			end repeat
		end ignoring
		
		tell oDoc
			set will autosave to true
		end tell
	end tell
	
	return {Inbox:lngInbox, Projects:lngProjects, Tasks:lngTasks}
	
end TP_OF



on Trim(someText)
	local someText
	
	repeat until someText does not start with " "
		if (length of someText) > 1 then
			set someText to text 2 thru -1 of someText
		else
			set someText to ""
		end if
	end repeat
	
	repeat until someText does not end with " "
		if length of someText > 1 then
			set someText to text 1 thru -2 of someText
		else
			set someText to ""
		end if
	end repeat
	
	return someText
end Trim

on RTrim(someText)
	local someText
	
	repeat until someText does not end with return
		if length of someText > 1 then
			set someText to text 1 thru -2 of someText
		else
			set someText to ""
		end if
	end repeat
	
	return someText
end RTrim

on ParseLevel(strLine)
	set lngLevel to 1 --Assume project headings and inboxes are zero
	repeat while strLine starts with tab
		set lngLevel to lngLevel + 1
		
		if length of strLine > 1 then
			set strLine to text 2 thru -1 of strLine
		else
			set strLine to ""
			exit repeat
		end if
	end repeat
	
	return {lngLevel, strLine}
end ParseLevel

on ParseTask(oDoc, strTask)
	-- Return recTask as property list for an Omnifocus Task
	set recTask to {}
	if length of strTask > 0 then
		set strOldDelims to text item delimiters
		
		set text item delimiters to " @"
		set lstParts to text items of strTask
		
		set recTask to {name:(item 1 of lstParts) as string} & recTask
		
		set lngParts to count of lstParts
		set blnContextSet to false
		if lngParts > 1 then
			
			set text item delimiters to "("
			ignoring case
				using terms from application "OmniFocus"
					repeat with strPart in rest of lstParts
						set lstTagVal to text items of strPart
						set strTag to item 1 of lstTagVal
						if (count of lstTagVal) > 1 then
							set strVal to rich text 1 thru -2 of (item 2 of lstTagVal)
						else
							set strVal to ""
						end if
						if length of strTag > 0 then
							if strTag ≠ "done" then
								if strTag ≠ "start" then
									if strTag ≠ "due" then
										if strTag ≠ "mins" then
											if (strTag ≠ "flag") then
												if blnContextSet then
													--Skip any additional context
												else
													set oCat to my GetContext(oDoc, strTag)
													if oCat ≠ missing value then
														set recTask to {context:oCat} & recTask
													end if
												end if
											else -- flagged
												-- set flag of recTask to true
												set recTask to {flagged:true} & recTask
											end if
										else -- mins
											try
												set lngMins to strVal as integer
												-- set mins of recTask to strVal
												
												set recTask to {estimated minutes:lngMins} & recTask
												
											end try
										end if
									else -- due
										-- set due of recTask to strVal
										set dteDue to my ParseDate(strVal)
										if dteDue ≠ 0 then
											set recTask to {due date:dteDue} & recTask
										end if
									end if
								else -- start()
									set dteStart to my ParseDate(strVal)
									if dteStart ≠ 0 then
										                                       set recTask to {defer date:dteStart} & recTask
									end if
								end if
							else -- done
								-- set zapped of recTask to true
								set recTask to {completed:true} & recTask
							end if
						end if
					end repeat
				end using terms from
			end ignoring
			
		else -- very short
			set recTask to {name:strTask}
		end if
		
		set text item delimiters to strOldDelims
	end if
	return recTask
end ParseTask

on GetContext(oDoc, strTag)
	using terms from application "OmniFocus"
		set strSum to strTag as string
		tell oDoc
			set oContexts to complete strTag as context maximum matches 1
			if length of oContexts > 0 then
				set oContext to context id (id of item 1 of oContexts)
			else --
				set oContext to make new context with properties {name:strTag}
			end if
		end tell
	end using terms from
	return oContext
end GetContext

on ParseDate(strDate)
	try
		set dte to date strDate
		set blnDate to true
	on error
		set strOldDelims to text item delimiters
		set text item delimiters to " "
		
		--try
		set lstDateTime to text items of strDate
		
		set blnDate to true
		try
			set strDate to item 1 of lstDateTime
			set text item delimiters to "-"
			set lstDateParts to text items of strDate
			set lngYear to item 1 of lstDateParts as integer
			set lngMonth to item 2 of lstDateParts as integer
			set lngDay to item 3 of lstDateParts as integer
		on error
			set blnDate to false
		end try
		
		set blnTime to true
		try
			set strTime to item 2 of lstDateTime
			set text item delimiters to ":"
			set lstTimeParts to text items of strTime
			set lngHours to item 1 of lstTimeParts as integer
			set lngMins to item 2 of lstTimeParts as integer
		on error
			set blnTime to false
		end try
		
		if blnDate then
			set dte to current date
			set hours of dte to 0
			set minutes of dte to 0
			set seconds of dte to 0
			
			set year of dte to lngYear
			set day of dte to 1 -- (All months have 1st, some lack 29-31)
			set month of dte to lngMonth
			set day of dte to lngDay -- (and now the day we want)
			
			if blnTime then
				if lngHours > 0 or lngMinutes > 0 then
					set hours of dte to lngHours
					set minutes of dte to lngMins
				end if
				
			end if
			
		end if
		
		set text item delimiters to strOldDelims
	end try
	
	if blnDate then
		return dte
	else
		return 0
	end if
end ParseDate

Thanks for the correction, I will certainly give them a spin and I’ll point the donatio toward the site. Double thanks.

/GL

Hello.

You know, it would be nice if you rewrote the variable names, in that handler a little, (in the current version), to what the variables meant or means to you, then I can, go back and add code that are in the same gist,with the code necessary for it to work with tasks under tasks, and nodes. I actually look forward to do it, as I think I have found a good solution to the expansion, and contraction of the “tree-view”.:slight_smile:

It is not that big a deal, but it is best if the variable names are clearer, because then the script is maintainable at some later stage, when something got to be changed (next version of Omnifocus for instance, or if you want more features). I also can’t test all the things in your script, because Omnifocus 2 has some terminology, that Omnifocus 1 (that I possess), doesn’t handle. I will mark those parts in the script.