The Sheets Hypercode Environment (or simply "Sheets") is an advanced programming environment for Java. In Sheets, programs are divided into fragments, and sheets are containers of fragments. Sheets are themselves fragments, so you can have nested sheets. The same fragment can exist on multiple sheets. When the fragment is edited on one sheet, the change is reflected on the other sheet the instant the edit is committed.
By internally representing programs this way, Sheets can provide features that other environments do not. In particular, Sheets provides very good navigation facilities -- with a single keystroke, you can find the definition of a method, or any place that calls it.
The easiest way to learn about Sheets is to try it out on real Java code. If you have some existing Java code, you can use the new project wizard to create a database. Simply run sheets with no arguments. The wizard's dialogs allow you to say what files to import, what package to use, etc.
Alternatively, you can use the SunDial demo project:
sheets SunDial.sheets
When Sheets starts up, you will get three windows:
To use most of the features of Sheets, you will need to open an edit window containing some code. Navigate starting in the projects window. You can expand subsheets by clicking on the plus sign (+), or can open a sheet in its own window by double clicking on it. If you expand a code sheet in the projects window using +, you'll see the names of all of the definitions, but can't do any editing. Double-click on the sheet you opened (which now has a -) to create an edit window for that sheet.
The edit window has two panels:
Note that the edit panel is not displaying all the code. Rather, each fragment is in the header view. Methods have names, parameter lists, and return types, but their implementation isn't shown. Similarly, for fields, the initial value is not shown. The code is still there, it just isn't displayed. To see the entire fragment, double-click on it.
Most fragments support three views:
The easiest way to change to any view is to use the right-click menu and select Show As Header, etc. Also, under the Container menu are commands for changing the view of all fragments on the sheet.
As in any other editor, left-click will move the cursor to the location that you clicked at. If you double left-click, on a fragment, you'll text-select the word under the cursor and turn the fragment into the full view at the same time. Similarly, if you double click on something in the TOC panel, you'll expand it into the full view in addition to moving the cursor there.
Sheets supports all the usual text editor features, with a few twists for fragment-based editing. Fragment editing has been added on as transparently as possible, but some operations can only be done at the fragment level, and fragment select/cut/paste works differently than a purely text based approach does.
As in most editors, a mouse-based selection mechanism is used to indicate blocks of stuff that should be moved, deleted, etc. In Sheets, the current selection can be either a text selection or a fragment selection.
A text selection works basically the same as the selection mechanism in any text editor. The selection is indicated by a mouse drag from one end of the selection to the other. However, in Sheets a text selection cannot extend across a fragment boundary. If you attempt to select more than one fragment by dragging, you will be baffled because the drag is interpreted as a fragment move from the start location to the end location.
A fragment selection selects one or more entire fragments. There is no way in Sheets to select the end of one fragment and the beginning of the next. The fragment that the cursor is in is always part of the selection, so you can select a single fragment by just left-clicking on it. This selection is indicated by the black line drawn around the current fragment.
You can select multiple fragments by using shift-left-click and control-left-click. shift-left-click selects all of the fragments between the current fragment and the mouse position. control-left-click adds a single fragment to the selection without deselecting any of the already selected fragments. If there is a multiple selection, all of the selected fragments have their background changed to yellow and are outlined by a red line box.
Once there is a multiple selection in effect, the only way to go back to the normal mode of having a single fragment selected is to click on some fragment that is not in the selection.
Note that this is not the same as selecting all of the fragments inside the sheet. If you cut and paste a sheet, you preserve the title and all of the other meta-information associated with the sheet.
When a sheet is selected, fragment operations such as Destroy will affect the sheet itself, and only implicitly affect the contents insofar as the affected sheet may be the only reference to those fragments. Some fragment opertations such as Fragment/Cut can only be done on subsheets of the current window, and not on the outermost sheet displayed in a window.
To edit a fragment, left-click to put the cursor inside the fragment and start typing. The fragment will switch to the full view and turn pink when you do this. If you want to edit a fragment that is not in the full view, you may not be able to see the text that you want to edit. In this case, double-click somewhere in the header to put the fragment in full view, find the code you want, and start editing.
When you are done making changes, you commit the edit via the Commit Edit option on the right-click menu or the green Commit button which appears at the bottom of the edited component. This explicit commit step serves two purposes: it tells Sheets when to redo syntactic and semantic analysis, and it allows a change to easily be discarded. Instead of commiting an edit, you can also abort it using the red Abort button or right-click Abort Edit. This discards any changes and places the fragment back as it was before editing began.
The pink color of an fragment being edited helps to to remind you that editing is incomplete. All fragments being edited also appear in the Fragment Edits window, which helps to keep track of multiple edits in progress. The ability to have several uncommited edits makes it easy to back out of an exploratory modification which spans several fragments.
Note that changes to a fragment are not written to the database until you commit the edit, so any uncommited edits will be lost on a system crash, power failure, etc.
A fragment must be syntactically correct before it can be commited. If there is a parse error, a pop-up error message is displayed and the fragment stays in edit mode.
The most general way to create a fragment is to use the Insert New submenu which is placed off the right-click menu and on the Fragment menu-bar menu. However, creating fragments is such a common operation that several shortcuts are also provided.
Java fragments and documentation paragraph fragments can be created by editing an existing Java fragment or documentation paragraph. When you commit an edit, parsing detects that there is more than one fragment in the result, and creates a new fragment of the same kind. When one fragment is replaced with two, this replacement is done in all sheets that contain the fragment; the new fragment is added to all sheets containing the old one.
Another way to create fragments is by "extending" an existing fragment. This rather poorly named operation has nothing to do with extending in the object-oriented sense, but simply means to create a new fragment like the current fragment and place it immediately after this fragment. Extending can be done by Fragment/Extend Fragment or by right-click Extend Fragment.
When an extension fragment is created, it is already in edit mode. If you decide you don't actually want a new fragment, you can make it go away by either commiting or aborting it. If you use "Commit Container Edits" (on the Edit and right-click menus), this will eliminate any extension fragments with no extra effort on your part.
As an additional convenience, if you create a new fragment by extending, and then commit it, the extend operation is automatically repeated. This makes it very easy to type in a sequence of the same type of fragment. When you are done adding fragments, there will be an extra empty extend fragment which you get rid of by commiting.
Sheets distinguishes between removing and destroying a fragment (we avoid the ambiguous term "delete".) Removing a fragment from a sheet means that the fragment will still exist, just not on the sheet you removed it from. Destroying a fragment, on the other hand, destroys it everywhere. To remove the selected fragment, select Remove fragment from the Fragment menu. To destroy a fragment, you can select Destroy fragment from the same menu.
If you edit a Java or Paragraph fragment to contain no text and then commit it, the result is no fragments. This is similar to destroying the fragment.
If you remove the last reference to a fragment, then it is automatically destroyed. In this case, removing and destroying are equivalent.
Both of these are useful operations, so there are two seperate commands: Fragment/Paste and Edit/Paste. By default, these are bound to ctrl-shift-V and ctrl-V.
The way that you get fragments into the clipboard is by using Fragment/Cut (ctrl-shift-X). If multiple fragments are selected, multiple fragments will be cut. Since there is often both a text and fragment selection, this command is distinct from Edit/Cut (ctrl-X). If the clipboard contains only text, then it can't be pasted as a fragment.
You can copy a fragment from one sheet to another by selecting the fragment and using Fragment/Copy (ctrl-shift-C.) When you paste the fragment on the new sheet, you will then have the same fragment on two different sheets. If instead, you want to make a new fragment with similar text in it, you can paste the fragment as text within an editable fragment.
Cutting a fragment is almost the same as removing it. Because the fragment may continue to exist in some other sheet, cutting a fragment is not a reliable way to remove it from the program. You should instead use Fragment/Destroy or right-click/Destroy Fragment, see Removing and Destroying. We recommend using cut only as a way to move fragments from one sheet to another, and to use remove or destroy when you want to remove or destroy.
Sheets support limited drag and drop. You can drag a fragment around on a sheet by holding down the mouse button over the fragment (not over the control block), moving the cursor to another fragment, and letting go of the mouse button. When you are dragging a fragment, a black line is drawn at the place where the fragment would be inserted if you drop at the current mouse position. You can do the dragging in either the edit panel or the TOC panel, although you can't start your drag in one panel and end in the other. If your mouse drag never crosses the fragment boundary, it will be interpreted as a text selection; your selection will turn yellow.
Deficencies in AWT prevent the implementation of drag and drop between seperate windows. However, you can drag a fragment between sheets when the sheets are displayed as inline sub-sheets in the same window.
Sheets has two different forms of undo: local undo and global undo. Local undo is capable of undoing text edits that happened during editing of a fragment before the edit is commited. Each edited fragment has its own local undo history. Local undo is invoked by Edit/Undo (ctrl-Z) and Edit/Redo (ctrl-Y) or right-click Undo Edit.
Global undo (Edit/Global Undo) backs up the state of the entire database, which will undo operations such as commiting an edit, destroying a fragment or moving a fragment within a sheet. When you run the global undo command, it pops up a dialog that allows you to step forward and backward through the global undo history.
There are two text areas describing commands in the history. The bottom pane displays the command which will be undone if you click on the Undo button. The top pane displays the command which you just undid (if any), and which will be redone if you click the Redo button.
When you've undone all the stuff that you want to undo, click Done in the global undo dialog. This closes the window and removes the commands that you have undone from the undo history; they can then no longer be redone. Normal sheets browsing can be done while the global undo dialog is active, but any command that modifies anything will close the dialog as though you had clicked Done.
One of the most important aspects of Hypercode is the ability to easily explore the underlying structure of the program. Sheets semantically analyzes Java code and automatically links identifiers to their uses, definition sites, etc. In addition, attributes can be used to create explicit links between conceptually related fragments. Sheets only knows about code that is in the database. If you want Sheets to know about third party libraries, or even standard Java libraries, then you must import these libraries or their summaries into Sheets. Usually you load Java summaries from the Java project in Java.sheets.
Once you have specified what you're looking for, you press one of the buttons on the right of the dialog. This tells Sheets to find what you're looking for, and also what to do with the results. The buttons require some explanation:
Because queries are very common operations, there are a lot of keyboard shortcuts available. Inside the query dialog, you can use control key combinations instead of pressing a "how to show it" button. There are also many shortcuts for launching the query dialog with the defaults set intelligently; for details see the section on Navigation commands.
The context window is itself a sheet, albeit a somewhat unusual one. You can select items in it, change the default view, even edit fragments in the context window. Also, you can double-click upon it to show the entire fragment in its original context. (This is a shortcut for the show-fragment-in-context command.)
The Search and Replace option in the Search menu provides traditional string-based search and replace. This command will search only the current sheet.
Normally, when a sheet is put in its own window, you will see both the edit panel and the table of contents panel. Sometimes, however, it's more convenient to hide one of the panels. You can do this on a temporary basis by using the Show Table of Contents and Show edit panel menu options in the Container menu. You can also hide the edit panel permanently by using the Container Properties dialog and setting the sheet's kind to Menu. For instance, you might want to do this to a sheet that contains only other sheets. The root sheet's kind is not menu, but it behaves very similarly.
The scratch sheet is meant to be a place where you can pull together all the fragments relevant to the task you're working on. You might use this space as a quick reference sheet for information the context window doesn't provide. Or you may use the scratch sheet to record and display all the queries you've performed. (See section Querying for details on sending queries to the scratch sheet) Like the context window, you can double-click on a fragment in order to view it in context.
Importing
is the process of taking code not written with Sheets, and bringing it into a Sheets database. To import a single Java file, use the Import File option from the File menu. This will convert the file into Sheets format, create a new sheet out of those fragments, and add the new sheet to the root sheet.To conveniently import many files at a time, you must use the Sheets command line interface. (This is because the standard Windows "Open File" dialog will not let you select a directory) See the section Command Line Usage for details.
Sheets is not aware of any code outside the database. One of the consequences of this is that if you want the context sensitive help feature to help you with the standard Java packages (like java.lang or java.awt), you will need to import the source code for those packages into Sheets. The Sheets distribution comes with summarized versions of five standard Java packages: java-lang.java, java-io.java, java-util.java, java-awt.java, and java-awt-datatransfer.java. Simply import any or all of these files into your database.
Exporting
is the process of taking Sheets hypercode, and turning it into files suitable for compilation by external file based Java compilers. There are three export options under the file menu. The first and third, Export this sheet and Export all sheets, should be pretty obvious. The second, Export dirty sheets, exports only those sheets that have been changed since the last export all or export dirty sheets. Note that The Files => Compile menu item implicitly exports dirty sheets.The result of an export is a text file suitable for compilation. Exported files are not meant to be viewed by humans (although in a pinch, they can be). One consequence is that with a team of programmers, either all developers should use Sheets, or none of them should -- programmers using Emacs will not want to edit files exported from Sheets. Exported files are human readable, but exporting will create a number of nuisances for the Emacs user. Most importantly, free-floating comments will be moved about (after all, compilers don't care about comments!). The good news is that if for some reason, you ever decide Sheets is not for you, you can take these exported files, spend a few hours reformatting the code, and go back to using Emacs.
The current implementation of exporting is fairly idiosyncratic, and will be replaced in the near future. For now, for any Java class you want to export, you should put it on a sheet that has its sheet kind set to Export each class to its own file (use Container Properties from the Container menu to set the sheet kind). Also, the sheet should contain all members of the class. (Sheets will warn you if the sheet does not contain all the class's members, but not before getting confused about which files are dirty and which aren't) Compilation Sheets is not a compiler, but it provides nice integration with off the shelf, file-based compilers. The concept of exporting is critical to compilation. If you are unfamiliar with exporting, you should read the section on exporting before proceeding. Also, you will need to perform a bit of additional setup in your .sheetsrc file to use compilation; see the section on compilation variables for details.
The Compile option under the File menu allows you to compile your program. This menu item will bring up a dialog box which gives you the option of compiling files which have changed since the last invocation or recompiling your program's entire set of files. When you select either compile or recompile, Sheets will export all dirty files and invoke the compiler.
If compiling your program produces errors, Sheets will create a new sheet of all fragments that had errors in them. Each line that had an error is flagged by a red arrow in the left margin. At actual error message text is displayed in the Errors attribute at the bottom of the fragment. Since the error sheet is a sheet, you can edit the fragments right there in the error listing. If you want to see the fragment in context, use right-clickShow In Context.
The default keybindings include use of the F5 key as the keyboard shortcut for compile-program, while control-F5 is the shortcut for recompile-program.
The compile dialog gives you several options. You can also change how Sheets invokes the compiler by editing either the compile-command or recompile-command strings fields. If you change this information, it will only last as long as your current Sheets session; to make permanent changes you must edit your .sheetsrc file; if you don't, it will default to /msdev/bin/nmake.exe. You must supply a fully qualified path for the command to run. (This is a limitation of Java.) There are two compilation strategies: explicit invocation of the compiler and implicity through nmake.
If you are building a simple program without the need to coordinate an existing project of several Java files, you may find it sufficient to invoke the compiler directly. Instead of the defaults in .sheetsrc you will probably want to create project specific compilation variable values which contain the compiler path and all the source Java files in a directory. Here is an example:
Nmake is especially useful if you want to manage several exported Java files. These files can each contain a separate class. In this case you will want to use a Makefile, rather than invoke the compiler directly; see the following section on Makefile support for details. Finally, if you're running on a Windows machine, you'll need to use wrapper.exe to run the make utility to pass arguments into nmake. Instead of writing
make argswrite
wrapper.exe nmake args
When you export files, Sheets will create a file named export-map.mak, which is useful for including in makefiles. It defines two makefile variables, EXPORTED_SRCS and EXPORTED_OBJS. EXPORTED_SRCS is all filenames that were exported since Sheets was started. EXPORTED_OBJS is the name of the object files that correspond to the source files exported. For example, if you exported Foo.java and Bar.java, then export-map.mak would look like
EXPORTED_SRCS = Foo.java Bar.java EXPORTED_OBJS = Foo.class Bar.classThe Makefile for building Sheets makes use of this facility. It does something like this:
!if EXIST(export-map.mak) !message Using export map !include export-map.mak !else !message No export map available EXPORTED_SRCS = EXPORTED_OBJS = !endif compile : $(EXPORTED_OBJS) # How to turn .java files into .class files .SUFFIXES : .java .class .java.class : $(JAVAC) -nowarn $*.java(Note that this example will work only under Microsoft nmake, because it uses the nmake preprocessor and nmake inference rules to turn .java files into .class files.) This example assumes that all editing is done inside Sheets, and that before Sheets is launched, all .class files have been compiled. For a slightly more robust version, see the real Makefile distributed with the Sheets source code.
To create a dump file, select Save to Dump File from the File menu. Sheets will ask you for a filename, and then save everything reachable from the root sheet. See section Command Line Usage for how to convert a dump file back into a database.
When working with multiple developers, it is frequently necessary to merge your work with others. Many version control systems provide a merge tool to do this semi-automatically; when the merge tool can't figure out how to merge properly, it will create a merge conflict. Sometimes Sheets can read a dump file with merge conflicts, and sometimes it can't. Just try converting the dump file into a database format (see previous paragraph). If Sheets can't handle the merge conflict, it will tell you, and you'll have to hand edit the dump file to resolve the conflict. (Don't worry -- the dump file format was designed to be human readable) If Sheets could read the dump file, you can locate the merge conflicts by using doing a Puke Green Query from the query dialog.
The sheets.bat executable supports three different command line syntaxes:
sheets [-uusername] databaseFile.sdb sheets [-uusername] databaseFile.sdb dumpFile.sheets sheets [-uusername] databaseFile.sdb [sourceFile.java | directoryName | wildcardExpression] …The first form is the simplest: You specify the database file to use, and optionally your user name (see below).
In the second form, you specify both a database file and a dump file. This converts the dump file into database format. If a database of that name already exists, it is replaced by the new database.
The third form allows you to conveniently import Java sources into Sheets. You specify the database file, and then a list of things to import. If the "thing" is a Java source file, Sheets will import that file into the database as if it were imported by using the File/Import File menu option. If the "thing" is a wildcard expression (like *.java), Sheets will expand the wildcard expression and do the obvious. And if "thing" is a directory, Sheets will import all Java source files in that directory and its subdirectories.
For all three command line syntaxes, if the database file does not exist, it will automatically be created for you in the same directory in which you started sheets.
The -u option is supported by all three syntaxes. The option allows you to specify the user name that will be used when writing out the dump file (see the section on dump files for an explanation of why you might want to do this). When using the -u option, there must not be any space between the -u and the user name -- i.e., -unkramer and not -u nkramer.
Most of the time, you can forget about the differences between Java and pseudo-Java, because when you commit a fragment with an unqualified name (like bar), Sheets will try to guess what class it belongs to. The rules are pretty simple. First, Sheets looks to see if the first fragment was a class definition; if it was, it uses that class name for the fragments which follow it. Otherwise, if you're editing another fragment, Sheets will use the class name from that old fragment. If both these heuristics fail, it will complain to you and use the name <unknown>.
Sheets is distributed with a number of example .sheetsrc files. See particularly sample.sheetsrc, which was designed specifically for new users to learn from.
In a .sheetsrc file, any line that begins with a pound sign (#) is considered a comment. .sheetsrc files are case sensitive.
When Sheets starts up, it initializes itself from the file .sheetsrc . (Sheets will first look for it in the current directory, and then in your home directory.) If this file does not exist, default settings are used. The .sheetsrc file can be used to create custom key bindings, or to change a few options. Several examples of .sheetsrc files are included in the release (look for *.sheetsrc, and particularly sample.sheetsrc).
Copyright (c) 1997 Carnegie Mellon University. All rights reserved.