Migrate fish_history from config to data dir

New implementation of migration code within the history_t class will
copy the contents of the old fish_history found in the config directory
to its new location in the data directory.  The old file is left intact.

This is done only in the event that a fish_history is not already found in
the data directory ($XDG_DATA_HOME/fish or ~/.local/share/fish).
This commit is contained in:
Jeff Kowalski 2015-09-18 20:47:38 -07:00 committed by David Adam
parent 4c2cc384d2
commit b13f0701a4
3 changed files with 71 additions and 15 deletions

View file

@ -1664,6 +1664,53 @@ bool history_t::is_empty(void)
return empty; return empty;
} }
/* Populates from older location (in config path, rather than data path)
This is accomplished by clearing ourselves, and copying the contents of
the old history file to the new history file. The new contents will
automatically be re-mapped later.
*/
void history_t::populate_from_config_path()
{
wcstring old_file;
if (path_get_config(old_file)) {
old_file.append(L"/");
old_file.append(name);
old_file.append(L"_history");
int src_fd = wopen_cloexec(old_file, O_RDONLY, 0);
if (src_fd != -1)
{
wcstring new_file;
history_filename(new_file, L"");
/* clear must come after we've retrieved the new_file name,
and before we open destination file descriptor,
since it destroys the name and the file */
this->clear();
int dst_fd = wopen_cloexec(new_file, O_WRONLY | O_CREAT, 0644);
char buf[BUFSIZ];
size_t size;
while ((size = read(src_fd, buf, BUFSIZ)) > 0) {
ssize_t written = write(dst_fd, buf, size);
if (written == -1) {
/*
This message does not have high enough priority to
be shown by default.
*/
debug(2, L"Error when writing history file");
break;
}
}
close(src_fd);
close(dst_fd);
}
}
}
/* Indicate whether we ought to import the bash history file into fish */ /* Indicate whether we ought to import the bash history file into fish */
static bool should_import_bash_history_line(const std::string &line) static bool should_import_bash_history_line(const std::string &line)
{ {

View file

@ -64,7 +64,7 @@ private:
/** Paths that we require to be valid for this item to be autosuggested */ /** Paths that we require to be valid for this item to be autosuggested */
path_list_t required_paths; path_list_t required_paths;
public: public:
const wcstring &str() const const wcstring &str() const
{ {
@ -141,7 +141,7 @@ private:
/** Whether we have a pending item. If so, the most recently added item is ignored by item_at_index. */ /** Whether we have a pending item. If so, the most recently added item is ignored by item_at_index. */
bool has_pending_item; bool has_pending_item;
/** Whether we should disable saving to the file for a time */ /** Whether we should disable saving to the file for a time */
uint32_t disable_automatic_save_counter; uint32_t disable_automatic_save_counter;
@ -222,7 +222,7 @@ public:
/** Add a new pending history item to the end, and then begin file detection on the items to determine which arguments are paths */ /** Add a new pending history item to the end, and then begin file detection on the items to determine which arguments are paths */
void add_pending_with_file_detection(const wcstring &str); void add_pending_with_file_detection(const wcstring &str);
/** Resolves any pending history items, so that they may be returned in history searches. */ /** Resolves any pending history items, so that they may be returned in history searches. */
void resolve_pending(); void resolve_pending();
@ -236,6 +236,9 @@ public:
/** Irreversibly clears history */ /** Irreversibly clears history */
void clear(); void clear();
/** Populates from older location ()in config path, rather than data path) */
void populate_from_config_path();
/** Populates from a bash history file */ /** Populates from a bash history file */
void populate_from_bash(FILE *f); void populate_from_bash(FILE *f);

View file

@ -1226,7 +1226,7 @@ static bool insert_string(editable_line_t *el, const wcstring &str, bool allow_e
size_t len = str.size(); size_t len = str.size();
if (len == 0) if (len == 0)
return false; return false;
/* Start inserting. If we are expanding abbreviations, we have to do this after every space (see #1434), so look for spaces. We try to do this efficiently (rather than the simpler character at a time) to avoid expensive work in command_line_changed() */ /* Start inserting. If we are expanding abbreviations, we have to do this after every space (see #1434), so look for spaces. We try to do this efficiently (rather than the simpler character at a time) to avoid expensive work in command_line_changed() */
size_t cursor = 0; size_t cursor = 0;
while (cursor < len) while (cursor < len)
@ -1236,14 +1236,14 @@ static bool insert_string(editable_line_t *el, const wcstring &str, bool allow_e
size_t char_triggering_expansion_pos = allow_expand_abbreviations ? str.find_first_of(expansion_triggering_chars, cursor) : wcstring::npos; size_t char_triggering_expansion_pos = allow_expand_abbreviations ? str.find_first_of(expansion_triggering_chars, cursor) : wcstring::npos;
bool has_expansion_triggering_char = (char_triggering_expansion_pos != wcstring::npos); bool has_expansion_triggering_char = (char_triggering_expansion_pos != wcstring::npos);
size_t range_end = (has_expansion_triggering_char ? char_triggering_expansion_pos + 1 : len); size_t range_end = (has_expansion_triggering_char ? char_triggering_expansion_pos + 1 : len);
/* Insert from the cursor up to but not including the range end */ /* Insert from the cursor up to but not including the range end */
assert(range_end > cursor); assert(range_end > cursor);
el->insert_string(str, cursor, range_end - cursor); el->insert_string(str, cursor, range_end - cursor);
update_buff_pos(el, el->position); update_buff_pos(el, el->position);
data->command_line_changed(el); data->command_line_changed(el);
/* If we got an expansion trigger, then the last character we inserted was it (i.e. was a space). Expand abbreviations. */ /* If we got an expansion trigger, then the last character we inserted was it (i.e. was a space). Expand abbreviations. */
if (has_expansion_triggering_char && allow_expand_abbreviations) if (has_expansion_triggering_char && allow_expand_abbreviations)
{ {
@ -1253,16 +1253,16 @@ static bool insert_string(editable_line_t *el, const wcstring &str, bool allow_e
} }
cursor = range_end; cursor = range_end;
} }
if (el == &data->command_line) if (el == &data->command_line)
{ {
data->suppress_autosuggestion = false; data->suppress_autosuggestion = false;
/* Syntax highlight. Note we must have that buff_pos > 0 because we just added something nonzero to its length */ /* Syntax highlight. Note we must have that buff_pos > 0 because we just added something nonzero to its length */
assert(el->position > 0); assert(el->position > 0);
reader_super_highlight_me_plenty(-1); reader_super_highlight_me_plenty(-1);
} }
reader_repaint(); reader_repaint();
return true; return true;
@ -1562,7 +1562,7 @@ static void accept_autosuggestion(bool full)
{ {
/* Accepting an autosuggestion clears the pager */ /* Accepting an autosuggestion clears the pager */
clear_pager(); clear_pager();
/* Accept the autosuggestion */ /* Accept the autosuggestion */
if (full) if (full)
{ {
@ -1877,7 +1877,7 @@ static bool handle_completions(const std::vector<completion_t> &comp, bool conti
break; break;
} }
} }
/* Determine if we use the prefix. We use it if it's non-empty and it will actually make the command line longer. It may make the command line longer by virtue of not using REPLACE_TOKEN (so it always appends to the command line), or by virtue of replacing the token but being longer than it. */ /* Determine if we use the prefix. We use it if it's non-empty and it will actually make the command line longer. It may make the command line longer by virtue of not using REPLACE_TOKEN (so it always appends to the command line), or by virtue of replacing the token but being longer than it. */
bool use_prefix = common_prefix.size() > (will_replace_token ? tok.size() : 0); bool use_prefix = common_prefix.size() > (will_replace_token ? tok.size() : 0);
assert(! use_prefix || ! common_prefix.empty()); assert(! use_prefix || ! common_prefix.empty());
@ -2660,7 +2660,13 @@ void reader_set_exit_on_interrupt(bool i)
void reader_import_history_if_necessary(void) void reader_import_history_if_necessary(void)
{ {
/* Import history from bash, etc. if our current history is empty */ /* Import history from older location (config path) if our current history is empty */
if (data->history && data->history->is_empty())
{
data->history->populate_from_config_path();
}
/* Import history from bash, etc. if our current history is still empty */
if (data->history && data->history->is_empty()) if (data->history && data->history->is_empty())
{ {
/* Try opening a bash file. We make an effort to respect $HISTFILE; this isn't very complete (AFAIK it doesn't have to be exported), and to really get this right we ought to ask bash itself. But this is better than nothing. /* Try opening a bash file. We make an effort to respect $HISTFILE; this isn't very complete (AFAIK it doesn't have to be exported), and to really get this right we ought to ask bash itself. But this is better than nothing.
@ -3157,7 +3163,7 @@ const wchar_t *reader_readline(int nchars)
editable_line_t *el = data->active_edit_line(); editable_line_t *el = data->active_edit_line();
insert_string(el, arr, true); insert_string(el, arr, true);
/* End paging upon inserting into the normal command line */ /* End paging upon inserting into the normal command line */
if (el == &data->command_line) if (el == &data->command_line)
{ {
@ -3440,7 +3446,7 @@ const wchar_t *reader_readline(int nchars)
{ {
begin--; begin--;
} }
/* Push end forwards to just past the next newline, or just past the last char. */ /* Push end forwards to just past the next newline, or just past the last char. */
size_t end = el->position; size_t end = el->position;
while (buff[end] != L'\0') while (buff[end] != L'\0')