Indexing help (or: macOS help viewer vs. DEVONthink)

A tip for all of us reading the help of DEVONthink 3 (or any other macOS help):

One can capture portions or entire pages of a help book by selecting and dragging content to the DEVONthink icon in the dock. This creates a webarchive and is very useful to extract information. Another way is to print the entire page as PDF to DEVONthink and then highlight what’s of interest.

For those who want to go a step further:

It’s possible to index a copy of the whole help in DEVONthink. I’ve done that with a lot of apps and use an extra database that only consists of help for different apps. This has a lot of advantages over the use of macOS help viewer:

  • search with DEVONthink
  • search help of apps that are not running
  • find connections between apps (e.g. export or import formats)
  • open links in tabs
  • open images in PhotoStickies
  • create webarchives by dragging

I’ve probably forgot to mention a lot more advantages… What I wanted to say: Don’t stick with macOS help viewer! Use DEVONthink instead, it’s - beneath a thousand other fantastic things - also a great help viewer :slight_smile:

To index DEVONthinks help:

  1. go to “/Applications/DEVONthink 3.app/Contents/Resources/DEVONthink.help” (or use “Show in Finder” to go to the app, right click, “Show package content” and navigate to the file)
  2. copy “DEVONthink.help”
  3. close the finder window
  4. create a new folder with a meaningful name, e.g “DEVONthink 3 - Help (indexed)” (I’m using a parent folder “Applications - Help” at root level and all application helps are subfolders of this)
  5. paste “DEVONthink.help”
  6. right click, then “Show package content”
  7. copy folder “Contents”
  8. go back to the folder you’ve created
  9. paste folder “Contents”
  10. delete file “DEVONthink.help”
  11. index the folder (“DEVONthink 3 - Help (indexed)”) in DEVONthink

If you want to use a whole help page in another database don’t just move it there as links to that page won’t work anymore and images will not be displayed. Create a webarchive by dragging instead and save this to the other database.

To see if an app has a full help book or at least some help html files use EasyFind.

(The idea of indexing help was inspired by an app I’ve accidently read about (it’s broken since Sierra).)

2 Likes

It’s funny, I came up with the essential idea a long time ago and having been using it for many, many years. :slight_smile:

However, I do not suggest copying and pasting the Help, for one because we are Mac users, not Windows :stuck_out_tongue: . Also, the Help is a moving target. Remember this is beta testing.
And also, it is subject to changing even in the public release. This means your resources will not be current.

Here is a much simpler approach…

  1. Create an appropriately named group in DEVONthink.
  2. Right-click the application in /Applications and choose Show Package Contents.
  3. Descend into the Contents/Resources folder.
  4. Right-click the <application>.help file and choose Show Package Contents and descend into the Contents folder.
  5. Index the Resources folder. So in this case, you are indexing /Applications/DEVONthink 3/DEVONthink 3.app/Contents/Resources/DEVONthink.help/Contents/Resources.
    Note the parent group in the screencap is not indexed.
  6. To access the Help, you select the DEVONthink HTML file.
    You can optionally add this file to the Favorites for quicker access.

A caveat is you should not reorganize or modify this indexed group and its contents. Ever.

PS: On the webarchive capture suggestion… If people have machines with an older OS, like Sierra, the webarchives are incompatible. (It’s an Apple issue.)

1 Like

It was a good idea but you know that :slight_smile: Wow I could have bet that it is strictly advised not to index something directly from within the application. I’ll change that as getting updated help files automatically is a even nicer setup. Thanks!

Wow I could have bet that it is strictly advised not to index something directly from within the application.

Generally speaking, it is inadvisable to mess about in the internals of an application or database. I was merely responding to your suggestion with my own approach.
This is also more academic than suggested, as YOU SHOULD NOT MODIFY THE INDEXED ITEMS for any reason.
You should also NEVER use Move into Database.

Hang on a second…

A safer approach… with the same WARNINGS:

set rsrc to ((path to application id "DNtp" as string) & "Contents:Resources:DEVONthink.help:Contents:Resources")

tell application id "DNtp"
	set helpLocation to create location "/DEVONthink 3 Help" in incoming group -- Index into the Global Inbox
	indicate rsrc to helpLocation
	set locking of helpLocation to true -- This will NOT lock it from edits.
end tell
--- And yes, this could be used for the help in another app by adjusting the rsrc path

Again, I am not advocating this as a general behavior.
It’s definitely possible you could muck things up if someone was being cavalier about it.

This script is done more as proof-of-concept as to what could be done (and because scripting is awesome and fun too!) :stuck_out_tongue:

Yeah scripting really is fun :smiley: Here’s what I came up with. Works although I have to admit I did not test a lot as I already had indexed all helps.

I decided to stay on the save side so the script copies the help book to a new folder AppName + theSuffix in theSuperFolderPath. While writing it came to my mind that it would make sense to only index the HTML files, doesn’t it? No idea at the moment how to filter everything else out…

-- Index app help
-- Includes code from Bluefrog
-- Usage with a dedicated database is recommended as everything is indexed, not just the "Index.html" as a "startpage".

-- Finder
property theAppsFolder : "/Applications/Fremdsoftware/"
property theSuffix : " - Hilfe (indiziert)" -- for new Finder folder
property theSuperFolderPath : "/Applications/Fremdsoftware - Hilfe/" -- path in Finder where 

-- DEVONthink
property theLocation : "/App Hilfe" -- location in database where new help folders will be indexed (e.g. "/App Hilfe/DEVONthink 3 - Hilfe (indiziert)")
property theDatabaseName : "Mac & Software - Hilfe (indiziert)"

tell application "System Events" to set activeApp to name of first application process whose frontmost is true
tell application "SystemUIServer"
	activate
	set theApp to choose file of type {"com.apple.application-bundle"} default location theAppsFolder
end tell
activate application activeApp

tell application id "com.apple.finder"
	try
		
		set theAppName to displayed name of theApp
		set theResources to files of folder ((theApp as string) & "Contents:Resources:")
		
		set helpBookFound to false
		repeat with thisResource in theResources
			if name extension of thisResource = "help" then
				set theHelpPath to thisResource as text
				set helpBookFound to true
				exit repeat
			end if
		end repeat
		
		if helpBookFound = false then
			tell application "System Events" to set activeApp to name of first application process whose frontmost is true
			tell application "SystemUIServer"
				activate
				set theDialog to display dialog "Keine Hilfe gefunden!" buttons {"Ok"} default button 1 with title "Hilfe indizieren"
			end tell
			activate application activeApp
			return
		end if
		
		set theFolderName to theAppName & theSuffix
		set theSuperFolder to folder (POSIX file theSuperFolderPath as alias)
		set theHelpContents to theHelpPath & "Contents"
		
		try
			
			set theNewFolder to make new folder at theSuperFolder with properties {name:theFolderName}
			duplicate folder theHelpContents to theNewFolder
			
		on error number error_number
			
			if the error_number is -48 then -- folder already exists
				tell application "System Events" to set activeApp to name of first application process whose frontmost is true
				tell application "SystemUIServer"
					activate
					set theDialog to display dialog "Es existiert bereits ein Ordner für diese App. Öffnen?" buttons {"Beenden", "Ok"} default button 2 with title "Hilfe indizieren"
				end tell
				activate application activeApp
				if button returned of theDialog = "Beenden" then
					return
				else
					set alreadyExists to folder (POSIX file (theSuperFolderPath & theFolderName) as alias)
					open alreadyExists -- manually delete old folder
					activate
					return
				end if
				
			else
				if the error_number is not -128 then
					display alert "Finder" & space & error_number message error_message as warning
					return
				end if
			end if
			
		end try
		
	on error error_message number error_number
		if the error_number is not -128 then
			display alert "Finder" & space & error_number message error_message as warning
		end if
		return
	end try
end tell


tell application id "DNtp"
	try
		
		set theSuperGroup to create location theLocation in database named theDatabaseName
		set theIndexedGroup to indicate theNewFolder as alias to theSuperGroup
		open window for record theIndexedGroup
		activate
		
	on error error_message number error_number
		if the error_number is not -128 then
			display alert "DEVONthink" & space & error_number message error_message as warning
		end if
		return
	end try
end tell

Technically, yes you could just used

set rsrc to ((path to application id "DNtp" as string) & "Contents:Resources:DEVONthink.help:Contents:Resources:DEVONthink.html")
and only index the main HTML file.

What I had in mind was to only index all HTML files of a copy of the help (not only the “Index.html” as entry to the other HTML files) and don’t index images and other stuff (this only clutters the database) If I understand it right HTML files should display properly as long as the relative paths of images etc. don’t change, but it should not be necessary to index those other stuff. If that’s correct indexing only HTMLs would result in a clutterfree and completely searchable help.

Looking into the dictionary, under indicate it says type is “obsolete”. How is filtering of what should be indexed done now? (Not sure if the old type would have been what I’m looking for)

One other thing, I’ve updated a little focus issue in the script and added “credentials” for your code. I’m sure thats not how it is done properly, are there any guidelines? Perhaps a silly question :sweat_smile:

I’ve updated a little focus issue in the script and added “credentials” for your code.

Not sure what you mean here.

Is this the “correct” way to tell other people that a script includes code from another person? I know it should be done, not sure how and if it always should be done

Ahh… hahaha! In here we probably don’t have to be so formal - though the inclusion is appreciated for sure. I just have some boilerplate in my scripts.

PS: Yeah, type is obsolete for indicate and you can only index all the items in a group. However, I don’t think it’s a huge burden in this case. And here’s a search on a fully indexed Help…

Jim, I presume you mean for us to navigate to /Applications from inside DT3, in order to index the appropriate folder?

Trying that here, has the DT3 application icon greyed out, with the right-click options being limited, and not allowing the “Show Package Contents” (which is obviously available when navigating to it via Finder)?

Or am I to Cmd-Opt the /DEVONthink.help/Contents/Resources folder into DT3, in order to Index it that way?

[Edit:] The latter option works, just want to check this is what was intended.

I presume you mean for us to navigate to /Applications from inside DT3, in order to index the appropriate folder?

To clarify, I don’t mean for anyone to do this, but if you choose to, you don’t navigate from within DEVONthink 3.

1 Like

I just wanted to see what would happen if I run this script lol (yes I know), and saw a red line just below the DevonThink icon from the Dock and then it started to download I don’t know what. I immediately closed DevonThink.

Now in “Recently added” I see a bunch of files, it looks like from the Help’s menu. It didn’t download all the files I assumed since I closed it before it finished downloading. I hope I didnt screw up the Help’s menu.

Can I delete these “recently added” files?
Also any other group that contain these files? I don’t see a group in Global inbox

No, it indexed the files. You can see that on the small Finder symbol to the right of the record names. And that’s what

does …

Why? Why oh why?

You have obviously no idea what the script is supposed to do, so why do you run it?

Bluefrog made a little mistake and mixed up incoming group and inbox. So the group is in the database that was your current database before you quit DEVONthink. Because you did a force quit you’ll probably have to open it manually. The group is in this database’s root.

NO!

Please wait until @bluefrog or @cgrunenberg tell you how to safely remove them.

I thought this was ascript to duplicate DevonThink 's Help’s menu to the Global inbox. well it freaked me out becasue I have never seen this red line under the DevonThink’s icon, thats why I stopped it.

Now I see where the group file is, the database I was in, there is 430 files there, obv Help’s partial files.

Thanks, we will see what he says.

You ran what script, mine or Pete’s?

yours lol

If you used mine - bearing in mind I issued more than one warning in this thread - you can delete the DEVONthink 3 Help group and empty the Trash. You should get the appropriate dialog about deleting indexed items and you’d obviously choose Only in Database.

Index DEVONthink help

This script indexes DEVONthink’s help.

It first duplicates the internal help to a new Finder folder, then indexes the duplicated help.

If you don’t like the indexed help anymore you can delete it without any risk.

How to index:

  • Run the script from Script Editor.app.

  • After 30 seconds you’ll find a new group in your global inbox.

  • You can move this group or rename it and/or the records in DEVONthink (not in Finder).

  • After a DEVONthink update delete the dated indexed help and run the script again.

How to delete:

  • Select the indexed group

  • Select menu Data > Show in Finder (but do nothing)

  • Switch back to DEVONthink

  • Move the indexed group to trash

  • Empty the trash

  • Switch back to Finder

  • Move the folder to trash (and confirm the dialog)

That’s it.

Thanks Jim, you’ve built a great resource!

-- Index DEVONthink help

-- This script first duplicates DEVONthink's internal help to a new Finder folder. You can delete the indexed group (e.g. after an update) without any risk.
-- Run the script from Script Editor.app. After 30 seconds you'll find a new group in your global inbox.
-- You can move this group or rename it and/or the records in DEVONthink (not in the Finder folder).
-- How to delete: https://discourse.devontechnologies.com/t/indexing-help-or-macos-help-viewer-vs-devonthink/46475/20

set theSuperFolder_Path to POSIX path of (path to application support from user domain) & "DEVONthink 3/DEVONthink Help (indexed)/"
set theResources_Path_HFS to ((path to of application id "DNtp") & "Contents:Resources:DEVONthink.help:Contents:Resources:") as string
set createSuperFolder to do shell script "mkdir -p " & quoted form of theSuperFolder_Path

tell application "Finder"
	try
		try
			set theSuperFolder to folder (POSIX file theSuperFolder_Path as alias)
		on error
			error theSuperFolder_Path
		end try
		try
			set theResourcesFolder to folder theResources_Path_HFS as alias
		on error
			error theResources_Path_HFS
		end try
		
	on error error_message number error_number
		activate
		if the error_number is not -128 then display alert "Finder" message "Can't get folder: \"" & error_message & "\"" as warning
		return
	end try
end tell

tell application id "DNtp"
	try
		set theHelpFolder_Name to "DEVONthink Help - " & version as string
		
	on error error_message number error_number
		if the error_number is not -128 then display alert "DEVONthink" message error_message as warning
		return
	end try
end tell

tell application "Finder"
	try
		try
			set theHelpFolder to make new folder at theSuperFolder with properties {name:theHelpFolder_Name}
		on error error_message number error_number
			if the error_number is -48 then
				error "Can't make folder. Folder already exists: \"" & theSuperFolder_Path & theHelpFolder_Name & "\""
			else
				error error_message number error_number
			end if
		end try
		
		duplicate folder theResources_Path_HFS to theHelpFolder
		set locked of entire contents of theHelpFolder to true
		set locked of theHelpFolder to true
		
	on error error_message number error_number
		activate
		if the error_number is not -128 then display alert "Finder" message error_message as warning
		return
	end try
end tell

tell application id "DNtp"
	try
		set theDatabase to inbox
		set theHelpGroup to indicate (theHelpFolder as alias) to root of theDatabase
		
		set thePath to path of theHelpGroup
		set locking of (contents of theDatabase whose path starts with thePath) to true
		set exclude from search of (contents of theDatabase whose path starts with thePath and type is not html) to true
		set exclude from see also of (contents of theDatabase whose path starts with thePath and type is not html) to true
		my excludeFrom(theHelpGroup)
		
		set theHTMLRecords to (contents of theDatabase whose path starts with thePath and type is html)
		
		repeat with thisHTMLRecord in theHTMLRecords
			set theSource to source of thisHTMLRecord as string
			try
				set thisTitle to (item 1 of (my tid(item 2 of (my tid(theSource, "<title>")), "</title>"))) as string
				if thisTitle ≠ "" then
					if thisTitle = "DEVONthink Documentation" then set thisTitle to "DEVONthink Documentation : " & (item 1 of (my tid(item 3 of (my tid(theSource, "<span class=\"topic\">")), "</span>"))) as string
					if thisTitle contains "&amp;" then set thisTitle to my replace_String(thisTitle, "&amp;", "&")
					if thisTitle ≠ "" then set name of thisHTMLRecord to theHelpFolder_Name & " - " & thisTitle
				end if
			end try
		end repeat
		
		try
			set theSmartGroup to create record with {type:smart group, search predicates:"kind:html", search group:theHelpGroup, name:theHelpFolder_Name} in theHelpGroup
			set theWindow to open window for record theHelpGroup
			set selection of theWindow to {get record at ((location of theHelpGroup as string) & (name of theHelpGroup as string) & "/Resources/" & theHelpFolder_Name & " - DEVONthink Help")}
			activate
		end try
		
	on error error_message number error_number
		activate
		if the error_number is not -128 then display alert "DEVONthink" message error_message as warning
		return
	end try
end tell

on excludeFrom(theGroup)
	tell application id "DNtp"
		try
			set locking of theGroup to true
			set exclude from classification of theGroup to true
			
			set theChildGroups to children of theGroup whose type is group
			repeat with thisChildGroup in theChildGroups
				my excludeFrom(thisChildGroup)
			end repeat
			
		on error error_message number error_number
			error number -128
		end try
	end tell
end excludeFrom

on tid(theText, theDelimiter)
	set d to AppleScript's text item delimiters
	set AppleScript's text item delimiters to theDelimiter
	set TextItems to text items of theText
	set AppleScript's text item delimiters to d
	return TextItems
end tid

on replace_String(theText, oldString, newString)
	local ASTID, theText, oldString, newString, lst
	set ASTID to AppleScript's text item delimiters
	try
		considering case
			set AppleScript's text item delimiters to oldString
			set lst to every text item of theText
			set AppleScript's text item delimiters to newString
			set theText to lst as string
		end considering
		set AppleScript's text item delimiters to ASTID
		return theText
	on error eMsg number eNum
		set AppleScript's text item delimiters to ASTID
		error "Can't replaceString: " & eMsg number eNum
	end try
end replace_String