File: //usr/share/jed/lib/session.sl
% jed session save/restore
%
% This file contains functions may be used to save and restore the
% partial state of a jed session. By partial, it is meant that only
% the names of the files that are associated with buffers, the
% positions within those buffers, and some of the buffer flags are
% saved. Other state information such as undo information,
% paste-buffers, etc are not saved.
%
% To use this file, add the following near the end of your .jedrc file:
%
% require ("session");
%
% Then when jed starts up with no filenames specified on the command
% line, it will attempt to load a session file from the startup
% directory. The files specified in the session file will be
% subsequently loaded. If jed is started with one or more files given
% on the command-line, the previous session will not be loaded, nor
% will the current one be automatically saved.
%
% By default, no session will be loaded or saved unless the startup
% directory contains a session file. To initiate the saving of a
% session, you can either execute the save_session function, or create
% an empty session file in the startup directory. If the save_session
% function is used, then the directory associated with the *scratch*
% buffer will be used for the session file.
%
% The name of the session file may be set using
% the Session_Filename variable. The default value is ".jedsession".
%
% The Session_Exclude_Patterns variable is a list of regular
% expressions that are matched against a filename. If a filename
% matches one of the patterns in the list, that filename will not be
% saved to the session file. The function session_add_exclude_pattern
% may be used to add patterns to this variable. Also, buffers that
% have the buffer-local variable save_session defined and set to 0
% will not be saved, as well as any buffer whose name begins with a
% space or '*' character.
%
% The format of the session file is very simple. It consists of zero
% or more lines formatted as:
%
% filename|linenumber|column|flags
%------------------------------------------------------------------------
%!%+
%\variable{Session_Filename}
%\synopsis{Name of the file where session information is saved}
%\usage{Session_Filename = ".jedsession";}
%\description
% The \svar{Session_Filename} function specifies the name of the file
% where session information is saved. If the filename is a relative
% one, then it will be regarded as relative to the startup directory.
%\seealso{}
%!%-
custom_variable ("Session_Filename", ".jedsession");
custom_variable ("Session_Exclude_Patterns", NULL);
public define session_add_exclude_pattern (pat)
{
if (Session_Exclude_Patterns == NULL)
Session_Exclude_Patterns = {};
list_append (Session_Exclude_Patterns, pat);
}
private variable This_Session_Filename = NULL;
private define expand_session_filename (file)
{
if (path_is_absolute (file))
return file;
variable dir;
(,dir,,) = getbuf_info ("*scratch*");
return path_concat (dir, file);
}
private define exclude_filename (file)
{
foreach (Session_Exclude_Patterns)
{
variable pat = ();
if (string_match (file, pat, 1))
return 1;
}
return 0;
}
public define save_session ()
{
variable session_file, do_error = 0;
if (_NARGS == 0)
{
session_file = Session_Filename;
do_error = 1;
}
else
session_file = ();
session_file = expand_session_filename (session_file);
variable files = {}, lines = {}, columns = {}, flags = {};
loop (buffer_list)
{
variable b = ();
variable file = buffer_filename (b);
if ((file == "") || (b[0] == ' ') || (b[0] == '*')
|| exclude_filename (file))
continue;
setbuf (b);
ifnot (get_blocal_var ("save_session", 1))
continue;
push_narrow ();
widen_buffer();
variable f; (,,,f) = getbuf_info ();
list_append (flags, f);
list_append (files, file);
list_append (lines, what_line());
list_append (columns, what_column());
pop_narrow ();
}
variable fp = fopen (session_file, "w");
if (fp == NULL)
{
variable msg = "Unable to save session to $file"$;
if (do_error)
throw msg;
message (msg);
return;
}
() = chmod (file, 0600);
_for (0, length(files)-1, 1)
{
variable i = ();
() = fprintf (fp, "%s|%d|%d|%#lx\n", files[i], lines[i], columns[i], flags[i]);
}
() = fclose (fp);
}
add_completion ("save_session");
private define load_session ()
{
variable do_error = 0, session_file;
if (_NARGS == 0)
session_file = Session_Filename;
else
{
do_error = 1;
session_file = ();
}
variable fp = fopen (session_file, "r");
if (fp == NULL)
{
if (do_error)
throw OpenError, "Failed to open session file ${session_file}"$;
return;
}
% Preserve the following flags:
% read-only (1<<3), overwrite (1<<4), crflag (1<<10)
variable mask = (1<<3)|(1<<4)|(1<<10);
variable str;
while (-1 != fgets (&str, fp))
{
if (str[0] == '%')
continue;
variable fields = strchop (str, '|', 0);
variable file, line, col, flags;
if ((length (fields) != 4)
|| (1 != sscanf(fields[1], "%d", &line))
|| (1 != sscanf(fields[2], "%d", &col))
|| (1 != sscanf(fields[3], "0x%x", &flags)))
throw DataError, "session file appears corrupt";
file = fields[0];
if (NULL == stat_file (file))
continue;
() = find_file (file);
if (bobp())
{
variable f;
goto_line (line);
if (is_line_hidden ()
&& (f = __get_reference ("fold_enter_fold"), f != NULL))
(@f)();
goto_column_best_try (col);
}
_set_buffer_flag (flags&mask);
}
() = fclose (fp);
This_Session_Filename = session_file;
}
private define startup_load_session_hook ()
{
if (whatbuf () != "*scratch*")
return;
load_session ();
}
add_to_hook ("_jed_startup_hooks", &startup_load_session_hook);
private define exit_save_session_hook ()
{
if (This_Session_Filename != NULL)
save_session (This_Session_Filename);
return 1;
}
add_to_hook ("_jed_exit_hooks", &exit_save_session_hook);