Buffer vs. File Coherence

From Niki

Jump to: navigation, search

Contents

Introduction

An editor should keep the highest possible coherence between:

  • The file currently edited (external data)
  • The buffer of this file (internal data)

Moreover, this coherence must be as safe as possible. It means that, unless specified by the user, no data (external or internal) must be lost.

Most of the time, this coherence is quite simple to maintain. If the buffer is modified (and no longer corresponds to the file on the harddisk), the modified flag is set.

Sometimes the situation can become tricky. This document is an attempt to list all the possible situations and to eventually give solutions that keep coherence and safety.



States

NEW_FILE the file is currently edited, but does not exist on disk yet
UNTITLED new window with no reference to any file
NORMAL 99 percent of the time...
READ_ONLY the file has read access but no write access
EXT_MODIFIED [1] the file has been modified by another program (and the coherence is lost)
NO_READ_ACCESS [1] the file has no read access (and the coherence is lost)
NO_FILE[1] the file is unreachable (and the coherence is lost)

Every state can be (So this is the state of the state? --Yooden):

  • MODIFIED or UNMODIFIED when the buffer is modified or unmodified
  • LOCKED or UNLOCKED when the set_locked() action routine is used (or not)


Events

CHECKING when focusing a X NEdit window for instance
REVERT_TO_SAVED when using the revert_to_saved() action routine
SAVE when using the save() action routine
CLOSE when using the close() action routine
NEW_BUFFER when using open(), new(), save_as() and when executing the command nedit or nc
LOCK_COMMAND when using the set_locked() action routine
MODIFICATION when a buffer is being modified
QUIT when using the quit() action routine

Some remarks:

  • The event LOCK_COMMAND can be considered a special case. Indeed, it is always possible to turn on and off the "locked" boolean of a buffer. The only special case seems to be when there is no write access. In that case, the message "read only" overrides the message "locked".
  • The event MODIFICATION can also be considered a special case. This event is always possible, except for: the READ_ONLY state, and in any state with LOCKED turned on. If a modification takes place when the buffer is UNMODIFIED, the buffer becomes MODIFIED.
  • QUIT is also a special case. It can be compared with CLOSE. Since I'm not totally convinced about that, I will note the differences in the following discussion.
  • I suppose that the NEW_BUFFER event has some special cases, according to the action that triggers it (open, save_as, new, nedit call...)


Different Possibilities

This table lists all the possible combinations of (STATE,EVENT). I think that a new check of the state should be done before any events (see Update state).

> Action 1 2 3 4 5
States CHECKING__REVERT_TO_SAVED__SAVECLOSENEW BUFFER
1__NEW_FILE__NONOYESYESNB, rem1
2UNTITLEDNONOYESYESNB, rem4
3NORMALYESYESYESYESNB
4__READ_ONLY__YESYESrem3rem5NB
5a__EXT_MODIFIED__W????NO
5b__NO_READ_ACCESS__W????NB
5c__NO_FILE__W????rem2

EASY: that should be trivial.

NO: the action is not possible, and is just ignored.

YES: this is supposed to be well handled by the current version of NEdit (5.3)

NB: When creating a new buffer, many problem can arise. Here are some problems I have noticed:

  • focus problem when calling nc with a file which already exists
  • nedit should use this event to do a new "update_state()"
  • when nedit tries a save_as(), I don't like the message: dialog("file exist in another window","cancel","close other window").

I think "close" should be "override" or "destroy, or something like that. 'I agree, and BTW, "exist" should be "exists". "Override other window" is my immediate thought. Or, "Save (overriding version in other window". Of course, if someone (you) then save that other window, you override what you just saved. Or, were you expecting that other window to be destroyed so that could not happen? If that is the case, maybe the message should be "Save (other window will be closed)"? (Sorry if I'm confusing the issue. -rhk)'

  • Moreover, if you press "close other window", you may have to answer if you want to reload the content of this "other window". But you don't care since you want to destroy it anyway.

W?: must nedit warn the user with a dialog box if the coherence is lost?

rem1: I'm not sure that the dialog box "file doesn't exist","new_file","dismiss" is necessary (indeed, the file is not really created).

rem2: if the file is a path, why not open an untitled window with the open dialog box. If the dialog box is closed without having selected any file, then the buffer is also closed.

rem3: when trying to save a "read only","modified" buffer, maybe it should be interesting

rem4: Why does the untitled buffer have no path?? I think that ALL nedit windows should have an associated path (which can be accessed, for instance, via the global variable $file_path). Talking about macros, I think that it's difficult to know the state of the nedit buffer (except modified and locked). Why not have a global variable &buffer_state??

rem5: A more specialised dialog box should be used here. Or maybe save_as()??

?: To be continued...


Update state

The state of a buffer sould be updated regularly:

  • before any events
  • when focusing the X window
  • automatically (every n minutes)

Let us call update_state() the function that is supposed to update the state of a buffer. The purpose of this function is to make a new measure of the status of the file currently edited:

  • date
  • size
  • read access
  • write access
  • content?? (to do a proper comparison)

And then, according to these new measures, the function update_state() should change the status of the file, eventually without any warning, since there is never any data loss.

The state might be be coded with an integer (7 possible states). The state can be seen while looking at the file name in the title bar, the statistic line, or the windows menu:

NEW_FILE"$filename" (why not "$filename (new file)")
UNTITLED"untitled" or "untitled_$n"
NORMAL$filename
READ_ONLY"$filename (read only)"
EXT_MODIFIED"$filename (externally modified)"
NO_READ_ACCESS"$filename (no read access)"
NO_FILE"untitled (was: $filename)"


The Buffer

I think that it's interesting to symbolically describe the undo system of the buffer. It can be considered as a list of different states, each state corresponding to a modification:

B_0  ->  B_1  -> ... ->  B_saved  -> ... ->  B_max

The rules are:

  • MOVE: until there are no modifications, it is possible to view any state of that list without any influence.
 B_0  ->  B_1  -> ... ->  B_saved  -> ... -> B_view -> ... -> B_max
  • MODIFY: as soon as a modification is made, the tail is cut:
 B_0  ->  B_1  -> ... ->  B_saved  -> ... -> B_view -> ... -> B_max

becomes:

 B_0  ->  B_1  -> ... ->  B_saved  -> ... -> B_max


  • MEMORY_CUT: I suppose that for some memory purpose, it is also possible to cut the head:
 B_0  ->  B_1  -> ... -> B_i -> ... ->  B_saved  -> ... -> B_max

becomes:

 B_i  -> ... ->  B_saved  -> ... -> B_max


Remarks:

  • It is possible that the saved buffer dissapears (in MODIFY and MEMORY_CUT). IMO, this is not a good thing because the loss of the saved buffer makes any serious comparison between the buffer and the file impossible. Consequently, it makes the recovery of the "coherence" impossible. Maybe a branching structure should be considered to keep track of the saved buffer:
 B_0  ->  B_1  -> ... ->  B_p  -> ... -> B_view -> ... -> B_max

and:

 B_p+1 -> ... -> B_saved


  • Anyway, The state of NO_SAVED_BUFFER of a buffer should be easily accesible (yes, another boolean). This can be very useful in the function that compares the file and the buffer: cmpBufAgainstFile()
  • In the case of NEW_FILE and UNTITLED, the saved buffer is the first one, and in fact corresponds to an initial empty buffer:
 B_empty (= B_saved) ->  B_1  ->  ... -> B_max


Conclusion

Well... I guess the conclusion is still to be done...