mirror of
https://github.com/fish-shell/fish-shell
synced 2024-12-26 12:53:13 +00:00
Re-implement $history variable
Added -L option to set to mean "don't abbreviate"
This commit is contained in:
parent
c8bc535f22
commit
1a87f44325
6 changed files with 60 additions and 157 deletions
|
@ -298,10 +298,10 @@ static void erase_values(wcstring_list_t &list, std::vector<long> &indexes)
|
|||
|
||||
|
||||
/**
|
||||
Print the names of all environment variables in the scope, with or without values,
|
||||
with or without escaping
|
||||
Print the names of all environment variables in the scope, with or without shortening,
|
||||
with or without values, with or without escaping
|
||||
*/
|
||||
static void print_variables(int include_values, int esc, int scope)
|
||||
static void print_variables(int include_values, int esc, bool shorten_ok, int scope)
|
||||
{
|
||||
wcstring_list_t names = env_get_names(scope);
|
||||
sort(names.begin(), names.end());
|
||||
|
@ -320,7 +320,7 @@ static void print_variables(int include_values, int esc, int scope)
|
|||
{
|
||||
int shorten = 0;
|
||||
|
||||
if( value.length() > 64 )
|
||||
if( shorten_ok && value.length() > 64 )
|
||||
{
|
||||
shorten = 1;
|
||||
value.resize(60);
|
||||
|
@ -385,6 +385,10 @@ static int builtin_set( parser_t &parser, wchar_t **argv )
|
|||
{
|
||||
L"universal", no_argument, 0, 'U'
|
||||
}
|
||||
,
|
||||
{
|
||||
L"long", no_argument, 0, 'L'
|
||||
}
|
||||
,
|
||||
{
|
||||
L"query", no_argument, 0, 'q'
|
||||
|
@ -400,7 +404,7 @@ static int builtin_set( parser_t &parser, wchar_t **argv )
|
|||
}
|
||||
;
|
||||
|
||||
const wchar_t *short_options = L"+xglenuUqh";
|
||||
const wchar_t *short_options = L"+xglenuULqh";
|
||||
|
||||
int argc = builtin_count_args(argv);
|
||||
|
||||
|
@ -410,7 +414,7 @@ static int builtin_set( parser_t &parser, wchar_t **argv )
|
|||
int local = 0, global = 0, exportv = 0;
|
||||
int erase = 0, list = 0, unexport=0;
|
||||
int universal = 0, query=0;
|
||||
|
||||
bool shorten_ok = true;
|
||||
|
||||
/*
|
||||
Variables used for performing the actual work
|
||||
|
@ -468,6 +472,10 @@ static int builtin_set( parser_t &parser, wchar_t **argv )
|
|||
universal = 1;
|
||||
break;
|
||||
|
||||
case 'L':
|
||||
shorten_ok = false;
|
||||
break;
|
||||
|
||||
case 'q':
|
||||
query = 1;
|
||||
break;
|
||||
|
@ -574,8 +582,6 @@ static int builtin_set( parser_t &parser, wchar_t **argv )
|
|||
wcstring_list_t result;
|
||||
size_t j;
|
||||
|
||||
// al_init( &result );
|
||||
// al_init( &indexes );
|
||||
env_var_t dest_str = env_get_string(dest);
|
||||
if (! dest_str.missing())
|
||||
tokenize_variable_array( dest_str, result );
|
||||
|
@ -612,7 +618,7 @@ static int builtin_set( parser_t &parser, wchar_t **argv )
|
|||
if( list )
|
||||
{
|
||||
/* Maybe we should issue an error if there are any other arguments? */
|
||||
print_variables(0, 0, scope);
|
||||
print_variables(0, 0, shorten_ok, scope);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -633,7 +639,7 @@ static int builtin_set( parser_t &parser, wchar_t **argv )
|
|||
}
|
||||
else
|
||||
{
|
||||
print_variables( 1, 1, scope );
|
||||
print_variables( 1, 1, shorten_ok, scope );
|
||||
}
|
||||
|
||||
return retcode;
|
||||
|
|
|
@ -1969,7 +1969,6 @@ void set_main_thread() {
|
|||
main_thread_id = pthread_self();
|
||||
}
|
||||
|
||||
|
||||
/* Notice when we've forked */
|
||||
static pid_t initial_pid;
|
||||
|
||||
|
@ -1987,7 +1986,7 @@ void setup_fork_guards(void) {
|
|||
initial_pid = getpid();
|
||||
}
|
||||
|
||||
static bool is_main_thread() {
|
||||
bool is_main_thread() {
|
||||
assert (main_thread_id != 0);
|
||||
return main_thread_id == pthread_self();
|
||||
}
|
||||
|
|
1
common.h
1
common.h
|
@ -739,6 +739,7 @@ double timef();
|
|||
This is our replacement for pthread_main_np().
|
||||
*/
|
||||
void set_main_thread();
|
||||
bool is_main_thread();
|
||||
|
||||
/** Set up a guard to complain if we try to do certain things (like take a lock) after calling fork */
|
||||
void setup_fork_guards(void);
|
||||
|
|
152
env.cpp
152
env.cpp
|
@ -1073,38 +1073,17 @@ const wchar_t *env_var_t::c_str(void) const {
|
|||
|
||||
env_var_t env_get_string( const wcstring &key )
|
||||
{
|
||||
scoped_lock lock(env_lock);
|
||||
|
||||
if( key == L"history" )
|
||||
/* Big hack...we only allow getting the history on the main thread. Note that history_t may ask for an environment variable, so don't take the lock here (we don't need it) */
|
||||
if( key == L"history" && is_main_thread())
|
||||
{
|
||||
wcstring result;
|
||||
const wchar_t *current;
|
||||
int i;
|
||||
int add_current=0;
|
||||
env_var_t result;
|
||||
|
||||
current = reader_get_buffer();
|
||||
if( current && wcslen( current ) )
|
||||
{
|
||||
add_current=1;
|
||||
result += current;
|
||||
history_t *history = reader_get_history();
|
||||
if (! history) {
|
||||
history = &history_t::history_with_name(L"fish");
|
||||
}
|
||||
|
||||
for( i=add_current;; i++ )
|
||||
{
|
||||
// PCA This looks bad! We can't do this off of the main thread.
|
||||
wchar_t *next = NULL;//history_get( i-add_current );
|
||||
if( !next )
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if( i!=0)
|
||||
{
|
||||
result += ARRAY_SEP_STR;
|
||||
}
|
||||
result += next;
|
||||
}
|
||||
|
||||
if (history)
|
||||
history->get_string_representation(result, ARRAY_SEP_STR);
|
||||
return result;
|
||||
}
|
||||
else if( key == L"COLUMNS" )
|
||||
|
@ -1125,6 +1104,8 @@ env_var_t env_get_string( const wcstring &key )
|
|||
}
|
||||
else {
|
||||
|
||||
scoped_lock lock(env_lock);
|
||||
|
||||
var_entry_t *res;
|
||||
env_node_t *env = top;
|
||||
wchar_t *item;
|
||||
|
@ -1183,119 +1164,6 @@ env_var_t env_get_string( const wcstring &key )
|
|||
}
|
||||
}
|
||||
|
||||
const wchar_t *env_get( const wchar_t *key )
|
||||
{
|
||||
ASSERT_IS_MAIN_THREAD();
|
||||
|
||||
var_entry_t *res;
|
||||
env_node_t *env = top;
|
||||
wchar_t *item;
|
||||
|
||||
CHECK( key, 0 );
|
||||
|
||||
if( wcscmp( key, L"history" ) == 0 )
|
||||
{
|
||||
const wchar_t *current;
|
||||
dyn_var.clear();
|
||||
|
||||
current = reader_get_buffer();
|
||||
if( current && wcslen( current ) )
|
||||
{
|
||||
dyn_var.append(current);
|
||||
dyn_var.append(ARRAY_SEP_STR);
|
||||
}
|
||||
|
||||
history_t *history = reader_get_history();
|
||||
if (history) {
|
||||
for (size_t idx = 1; idx < (size_t)(-1); idx++) {
|
||||
history_item_t item = history->item_at_index(idx);
|
||||
if (item.empty()) break;
|
||||
|
||||
dyn_var.append(item.str());
|
||||
dyn_var.append(ARRAY_SEP_STR);
|
||||
}
|
||||
}
|
||||
|
||||
/* We always have a trailing ARRAY_SEP_STR; get rid of it */
|
||||
if (dyn_var.size() >= wcslen(ARRAY_SEP_STR)) {
|
||||
dyn_var.resize(dyn_var.size() - wcslen(ARRAY_SEP_STR));
|
||||
}
|
||||
|
||||
return dyn_var.c_str();
|
||||
}
|
||||
else if( wcscmp( key, L"COLUMNS" )==0 )
|
||||
{
|
||||
dyn_var = to_string<int>(common_get_width());
|
||||
return dyn_var.c_str();
|
||||
}
|
||||
else if( wcscmp( key, L"LINES" )==0 )
|
||||
{
|
||||
dyn_var = to_string<int>(common_get_height());
|
||||
return dyn_var.c_str();
|
||||
}
|
||||
else if( wcscmp( key, L"status" )==0 )
|
||||
{
|
||||
dyn_var = to_string<int>(proc_get_last_status());
|
||||
return dyn_var.c_str();
|
||||
}
|
||||
else if( wcscmp( key, L"umask" )==0 )
|
||||
{
|
||||
dyn_var = format_string(L"0%0.3o", get_umask());
|
||||
return dyn_var.c_str();
|
||||
}
|
||||
|
||||
while( env != 0 )
|
||||
{
|
||||
var_table_t::iterator result = env->env.find(key);
|
||||
if ( result != env->env.end() )
|
||||
{
|
||||
res = result->second;
|
||||
}
|
||||
else
|
||||
{
|
||||
res = 0;
|
||||
}
|
||||
|
||||
|
||||
if( res != 0 )
|
||||
{
|
||||
if( res->val == ENV_NULL )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return res->val.c_str();
|
||||
}
|
||||
}
|
||||
|
||||
if( env->new_scope )
|
||||
{
|
||||
env = global_env;
|
||||
}
|
||||
else
|
||||
{
|
||||
env = env->next;
|
||||
}
|
||||
}
|
||||
if( !proc_had_barrier)
|
||||
{
|
||||
proc_had_barrier=1;
|
||||
env_universal_barrier();
|
||||
}
|
||||
|
||||
item = env_universal_get( key );
|
||||
|
||||
if( !item || (wcscmp( item, ENV_NULL )==0))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return item;
|
||||
}
|
||||
}
|
||||
|
||||
int env_exist( const wchar_t *key, int mode )
|
||||
{
|
||||
var_entry_t *res;
|
||||
|
|
26
history.cpp
26
history.cpp
|
@ -271,6 +271,32 @@ void history_t::add(const wcstring &str, const path_list_t &valid_paths)
|
|||
this->add(history_item_t(str, time(NULL), valid_paths));
|
||||
}
|
||||
|
||||
void history_t::get_string_representation(wcstring &result, const wcstring &separator)
|
||||
{
|
||||
scoped_lock locker(lock);
|
||||
|
||||
bool first = true;
|
||||
|
||||
/* Append new items */
|
||||
for (size_t i=0; i < new_items.size(); i++) {
|
||||
if (! first)
|
||||
result.append(separator);
|
||||
result.append(new_items.at(i).str());
|
||||
first = false;
|
||||
}
|
||||
|
||||
/* Append old items */
|
||||
load_old_if_needed();
|
||||
for (std::deque<size_t>::const_reverse_iterator iter = old_item_offsets.rbegin(); iter != old_item_offsets.rend(); ++iter) {
|
||||
size_t offset = *iter;
|
||||
const history_item_t item = history_t::decode_item(mmap_start + offset, mmap_length - offset);
|
||||
if (! first)
|
||||
result.append(separator);
|
||||
result.append(item.str());
|
||||
first = false;
|
||||
}
|
||||
}
|
||||
|
||||
history_item_t history_t::item_at_index(size_t idx) {
|
||||
scoped_lock locker(lock);
|
||||
|
||||
|
|
|
@ -147,6 +147,9 @@ public:
|
|||
/** Irreversibly clears history */
|
||||
void clear();
|
||||
|
||||
/* Gets all the history into a string with ARRAY_SEP_STR. This is intended for the $history environment variable. This may be long! */
|
||||
void get_string_representation(wcstring &str, const wcstring &separator);
|
||||
|
||||
/** Return the specified history at the specified index. 0 is the index of the current commandline. (So the most recent item is at index 1.) */
|
||||
history_item_t item_at_index(size_t idx);
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue