|
Home Pages Pidgin Azarennya (S|N) Mac Thesaurus Reference ToDo Colino Food Local Blogs: BadIdea Rachel RIAA Cult: Clambake Infidels Fi: Arda StarTrek Trek/Wars Film: IMDB D Harry Jabootu Kyle Fun: Agony ICanHas? ObSkills Snopes Lang: ZBB Vreleksá AwkWords Omniglot Scriptorium More... Local: Maps Map MyWeb Metro (map) FC Weather GoWhere? GGWash DC Arlington Reston Beyond Bacon Pix: Deviant Places Renderosity Blender Artists Pol: Anchoress Lizards Lucianne Strata WAwakes Sci: SmallThings Darwin AntiEvo Skeptics EvC BAUT Physics /.Sci Junk Panda Pharyngula Mags AmSci NatG Space X86: OSX86 ArsTech OSNews TUAW Dev PowWeb PHP Webmaster Coding Walkers Prog: PHP JS Toolbox Unobt Compress RegExp (test) Lint SQL Cocoa Builder Dev Apple BBS Userland Faqin Science/Tech: Engadget Thunderbolts Icecap Centauri NewSci Gizmodo co2sci ClimateDebate SciDaily Nrich NatGeog Math CreatClaims GoodBadMath CurrentEvents: OrigSig Flamingo FlopAces ImmigProf ~J~ MyVRWC NewsGroper Pal2Pal Sanity Simon TCS Toldjah Blogs... Tools: Calculator AsciiArt XMLVal FunStuff: Pictures: Photobucket (eg Dubai) Videos: YouTube Subtitler InterestingThings: LibraryThing FlashCards GoogleDocs Wowio Bubbl.us Colemak Audible PodioBooks WonderfulInfo BooksOnline AboutUs.org |
Notes /
Notes(See VersionOne.) IntroductionAs of 2007-01-16, I'm thinking about writing a note application, but I've swung back to wanting to store notes as text, so they can be edited in a regular text editor. Considerations
Macros and intermediate language (IL)IMPORTANT UPDATE!!! I am reconsidering stacks. Maybe a routine needs instead its own sequence. The first item is TRUE to return it to its caller and FALSE to return nothing. The second item can be anything -- an atom, a sequence, whatever should be appended to the caller's own sequence when the routine returns (if the first item is TRUE). So when you specify a literal string, it goes into a "stack" reserved for the next word you call. (This next word could be something like "stash" to put the contents of this "stack" into the "stack" of the current routine instead, or "dup" to copy the item without removing it from the stack intended for the word to be called.)
QueriesHow are queries done? If the IL interpreter is a fundamental part of the application, then maybe queries are macros (IL sequences) -- words on the dictionary. A query word would just test the current note and set a built-in flag to TRUE if the note matches the criteria or FALSE if not. Let's say we have a query like this:
So the resulting macro looks like this: "((K:system))" match? ifso "drove off" match? First, a literal string is pushed onto the stack. Next, the word A query with more options calls special routines to set or clear these options. For example: "car" ignore_case start_word match? ifso "drove off" whole_words match? OrganizationThe program should take its list of subjects from the names of the files in the data folder, e.g., "Reminders.n", "To-do.n", "Contacts.n", etc. InterfaceKeyboard
EuphoriaIf I write the software in Euphoria, then I have the source code and can add features later -- like macros. File I/OFile operations are easy. Reading notes from a fileThis should be a procedure that sets ilFlag to TRUE if the file was read successfully and FALSE if not. The file is read in as a sequence of notes, which in turn is placed, along with the path to the file, into another sequence which in turn is saved into the "notes" sequence, which is thus a gathering of all open files. To read a file, open() it and use gets() to read each line (including final "\n"):
constant div = "#<{[NOTE]}>#"
constant divlen = length(div)
sequence ilStack, notes
integer ilFlag
procedure fileOpen()
-- get filename from ilStack
-- set ilFlag = TRUE on success, FALSE otherwise
sequence filename, buffer, file
object line
integer fn, max
filename = popStack()
fn = open(filename, "r")
if fn = -1 then
ilFlag = FALSE
return
end if
buffer = {}
while 1 do
line = gets(fn)
if atom(line) then exit end if
max = length(line)
if max > divlen then max = divlen end if
if equal(div, line[1..max]) then
file &= {buffer}
buffer = ""
else
buffer &= line
end if
buffer = append(buffer, line)
end while
if not equal(buffer, "") then
file &= {buffer}
end if
close(fn)
notes &= {filename, file}
-- current file = notes[$]
ilFlag = TRUE
end procedure
Writing notes to a fileTo save the file, you just reverse the process: After each note, if there is another note, you append the note-boundary line.
sequence line, divider
integer fn
fn = open("myfile.txt", "r")
if fn = -1 then
puts(1, "Couldn't open myfile.txt\n")
abort(1)
end if
divider = div & "\n"
for i = 1 to length(notes) do
line = notes[i]
if not equal(line, "") then
puts(fn, divider)
puts(fn, line)
if line[$] != '\n' then
puts(fn, "\n")
end if
end if
end for
close(fn)
Finding textUse wildcard_match() (include wildcard.e) to find text (also use upper() or lower() for case-insensitive wildcard searches). Note that an asterisk matches zero or more characters and a question mark matches any single character. A query is a series of patterns (a sequence of sequences) to match against a sequence (note). Each pattern sequence is used as a filter. So to match a note against a query, you compare each pattern in the current filter to the text of the note using either match() or wildcard_match(), and if none of these calls return zero, then you have a match. Setting up the dictionaryStore words and definitions in separate sequences for faster access:
sequence words, defs
words = {
"dup"
, "drop"
, "swap"
-- and so on
}
defs = {
routine_id("dup")
, routine_id("drop")
, routine_id("swap")
-- and so on
}
Macro languageYes, I'll eventually want to automate the application. This means working out a macro language. I'll want to store macros as text, so that they can be read. However, the macro interpreter will translate this text into a sequence of routine_ids and then execute the routine_ids. I'll want to record macros. Each keystroke that activates a command or sets a variable or option will need to be translated into a "word" (the name of a procedure). Forth-like setupThe language is stack-based, so it looks "backwards" to some people, but there is no need to lump words into phrases before they make sense. Thus, each word is a command that does something. The language consists only of words and literal strings. Lines of the language look like this: ignore_case use_wildcards "s*thin* happen?" find "New topic.n" saveas -- saves current file as "New topic" Handling wordsA word corresponds to an entry in a "dictionary." Each entry in the dictionary contains two sequences: (1) the word itself, and (2) the word's "code." The code consists of atoms (routine_ids for internal routines that are part of the application, or indexes to other words in the dictionary) and sequences (literal strings). When the interpreter encounters a word at runtime, it runs the code stored in that word's dictionary entry. Handling literal stringsA word that begins with a doublequote triggers the interpreter's "quote mode," which causes the interpreter to put the following words into one long string that will go on the top of the stack -- until a single doublequote is found, which terminates quote mode. (A double doublequote inside a string -- "" -- is treated as part of the string and is converted to a single doublequote.) When the interpreter encounters a literal string at runtime, it pushes the string onto the stack. (Commands like Compiling calls to words
-- Application initialization
sequence word_definitions
word_definitions = {
routine_id('fileOpen'),
routine_id('fileSave'),
routine_id('filePrint'),
routine_id('editUndo')
-- etc.
}
constant userIDs = length(word_definitions) + 1
----------------------------------------
-- Macro interpreter loop
if id < userIDs then
call_proc(word_definitions[id], {})
else
call_word(id)
end if
Etc.The macro recorder typically gathers printable keystrokes into strings, which are passed to an Also note the implications here for gathering things into larger objects. If a query consists of patterns, each of which consists of a string and some options, then you define the strings and options first, then make them a pattern. (Patterns go onto their own stack.) After you've defined all of your patterns, you define the query, using all of the patterns on the pattern stack. DictionaryThe macro language has a built-in dictionary and a user-defined dictionary. When you record a macro, the macro automatically gets a name, with something like The dictionary itself is a sequence of dictionary entries. Each entry has two parts: a sequence (the procedure name, or "word") and an integer (a routine_id for the corresponding procedure, or an index into another sequence of other routine_ids. So the interpreter takes a macro in text form and generates a sequence that the interpreter interprets. If an element of the sequence is an atom, it is either a routine_id or the ID of another interpreter sequence. If the element is another (sub)sequence, then it is a literal string to be pushed onto the stack. Macro fileMacros should be saved to a file, in text form, as notes. So the system might have a "Macros.n" file. (An interpreter needs to be able to make sense of the contents of a note, and to find macros quickly, so a macro needs a special keyword, such as [/@macro/]. Also, the default behavior of the application is to summarize each note with the note's first line of printable text, so the recorder saves the macro's name, the word, as the first line ("def" goes on the line below). |