The Tycho API (tentative) ========================= app = Tycho.new(path=some_default) Start a Tycho instance and load the datastore app.current_topic Return the current topic (as an object). app.topics List of top-level topics. app.topic_titles List of the titles of top-level topics. Equivalent to: app.topics.map {|x| x.title } app.root Return the toplevel topic (root of tree) app.root = topic ??? Change the root to the specified topic, ignoring the rest of the tree. app.load(key) app[key] Load the topic or note specified by key app.load_topic(key) Load the topic specified by key (error if not a topic key) app.load_note(key) Load the note specified by key (error if not a note key) app.find_topic(tag) app.find_topic {|topic| ... } Find and open the top-level topic named by "tag" (which may be a string or regex). If there is more than one, an exception is raised. If a block is specified, a "true" value returned indicates a match. app.find_topics(tag) app.find_topics {|topic| ... } Find every top-level topic named by "tag" (which may be a string or regex). An array is returned. If a block is specified, a "true" value returned indicates a match. app.find_topic!(tag) app.find_topic! {|topic| ... } Find and open a topic named by "tag" (which may be a string or regex). If there is more than one, the first will be used. The entire tree is searched. If a block is specified, a "true" value returned indicates a match. app.find_topics!(tag) app.find_topics! {|note| ... } Find every topic named by "tag" (which may be a string or regex). An array is returned. The entire tree is searched. If a block is specified, a "true" value returned indicates a match. topic.find_topic(tag) topic.find_topic {|topic| ... } topic.find_topics(tag) topic.find_topics {|topic| ... } topic.find_topic!(tag) topic.find_topic! {|topic| ... } topic.find_topics!(tag) topic.find_topics! {|topic| ... } Search only under the specified topic. app.find_note(tag) # From root, find first match (no recursion) app.find_note {|note| ... } app.find_notes(tag) # From root, find all matches (no recursion) app.find_notes {|note| ... } app.find_note!(tag) # From root, find first match (recursing) app.find_note! {|note| ... } app.find_notes!(tag) # From root, find all matches (recursing) app.find_notes! {|note| ... } topic.find_note(tag) # From topic, find first match (no recursion) topic.find_note {|note| ... } topic.find_notes(tag) # From topic, find all matches (no recursion) topic.find_notes {|note| ... } topic.find_note!(tag) # From topic, find first match (recursing) topic.find_note! {|note| ... } topic.find_notes!(tag) # From topic, find all matches (recursing) topic.find_notes! {|note| ... } Analogous to find_topic. app.new_topic(topic_name) # create under top level app.current_topic.new_topic # create under current topic topic.new_topic(topic_name) # create under other specified topic Create a new topic. A Topic object is returned, to which you may add subtopics and notes. topic.new_note(title,contents=nil) topic.new_note {|note| ... } Create a new note under topic, with the given title and contents. A Note object is returned. topic.topic topic.parent # alias The parent topic of this topic (nil if receiver is root). topic.topics List of subtopics under topic. topic.topic_titles List of titles of subtopics under topic. Equivalent to: topic.topics.map {|x| x.title } topic.notes A list of Note objects for the specified topic. topic.note_titles A list of note titles for the specified topic. Equivalent to: topic.notes.map {|x| x.title } note.metadata.title = str note.title = str # special case Change the title of a note. Any other piece of metadata may be accessed, changed, or added on the fly in the same way. note.topic note.parent # alias The parent topic of this note. Tycho Metadata ============== Note that some metadata items are "heritable" -- that is, they may be inherited by subtopics without having to be specified again. This is indicated by a capital letter in the list below. For example: The item 'foobar' will not be inherited, but 'Foobar' will. In other respects, these have the same meaning. When an item is inherited by a subtopic, it may still be overridden by a local item. A special case is 'keywords' which does not override its parent, but merges the list of keywords. (This behavior may change.) If a metadata item starts with the prefix 'note_' then it applies to the notes in that topic rather than to the topic itself. This prefix may be capitalized ('Note_') if inheritance is desired. These are not explicitly copied into the metadata for the individual notes (but this behavior may change). Standard metadata for topics: title Topic title created Date/time created modified Date/time modified accessed Date/time accessed found Date/time found in search access_count Number of times accessed found_count Number of times found in search Sort Sort by: title, oldest, newest, recent, fresh, stale, often, seldom, manual (or add - to any of these) Actions Array for right-click menu? Each item has a label and a script name (or one-liner such as: system("...") ) manual_sort The manual sort key (maintained automatically) Note_* Metadata applying to all the notes under this topic Keywords Comma-separated list of keywords (array). Expanded Tree is initially expanded if true. GUI metadata for topics: expanded Is this subtree expanded by default? (Other items will likely be added.) User metadata for topics: Any metadata name that is not standard (including GUI) is assumed to be user-defined. The rule of 'capitalization for inheritance' applies as usual. Standard metadata for notes: title Note title created Date/time created modified Date/time modified accessed Date/time accessed found Date/time found in search access_count Number of times accessed found_count Number of times found in search sort Sort by: title, oldest, newest, recent, fresh, stale, often, seldom, manual (or add - to any of these) autosort If true, sort note by lines after each edit actions Array for buttons (or right-click menu??). Each item has a label and a script name (or one-liner). keywords Comma-separated list of keywords (array). script If true, note is an executable script. type Data type (mime?) -- always text for now (the default). template If true, this note serves as prototype for each new note in this topic (normally excluded from searches??). template_fields List of metadata fields copied into new note metadata? size Number of bytes in note. lines Number of lines in note. (Hmm: Assumes text.) GUI metadata for notes: window_width0 Initial computed window width. window_height0 Initial computed window height. window_x0 Initial x placement of upper left corner. window_y0 Initial y placement of upper left corner. window_width Manually resized window width. window_height Manually resized window height. window_x Manual x placement of upper left corner. window_y Manual y placement of upper left corner. User metadata for topics: Any metadata item that is not standard (including GUI) is assumed to be user-defined. Possible future standard metadata uses: Which user/instance of the program initiated this add/change/delete? Make topics or notes read-only? Protect topics/notes from being deleted? Allow a note to refer to an external file rather than storing the data? Allow hidden topics/notes? Allow password protection or security on topics/notes? Implementation notes ==================== I want to store the topics in a table of their own. That way, I can load the tree very quickly. Only the "current" topic will need to have its notes loaded -- in fact, maybe even only a few of those (since most may not be visible simultaneously in the GUI). I'm thinking that each topic or note should be identified by a key of some kind. In the early days of Tycho, this was an actual path, something like "data/dir001/dir001/note004.yaml" -- I think I want to keep the hierarchy, but obviously the old notation is too verbose. I'm leaning toward something similar but more compact -- let a topic ID be followed by a colon, and a note ID by a period. Let an ID be a number. Then a certain topic might be specified as "1:23:8" (a third-level topic); and a note within it might be "1:23:8.14" (or some such). This way, we can always tell where in the tree we are; and much of the tree can be recreated even if a parent node is corrupted. So the topics will be stored in a table with at least two fields -- the key and the title. In fact, a topic consists of little more than metadata -- perhaps we should just let the table of standard metadata be the topic table itself. In case there was any user-defined topic metadata, it would be stored in (say) topic_udm. But in what form? The field names are not predictable and may not be the same for different topics. I propose a key field and a data field; the latter would consist of a YAML'd object -- an array of arrays of the form [[name1,value1],[name2,value2],...] A hash might suffice, but I'd rather preserve order in case I wanted it later. As for the notes, I propose storing them in three tables: note_sm (standard metadata), note_udm (user-defined metadata) and note_data. The key would be duplicated in all of these. The note_udm would be stored in the same was as the topic_udm table. On the other hand: I *could* store the user-defined metadata as a single field in table with the standard metadata. Hmmm.