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,
|
Print the names of all environment variables in the scope, with or without shortening,
|
||||||
with or without escaping
|
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);
|
wcstring_list_t names = env_get_names(scope);
|
||||||
sort(names.begin(), names.end());
|
sort(names.begin(), names.end());
|
||||||
|
@ -320,7 +320,7 @@ static void print_variables(int include_values, int esc, int scope)
|
||||||
{
|
{
|
||||||
int shorten = 0;
|
int shorten = 0;
|
||||||
|
|
||||||
if( value.length() > 64 )
|
if( shorten_ok && value.length() > 64 )
|
||||||
{
|
{
|
||||||
shorten = 1;
|
shorten = 1;
|
||||||
value.resize(60);
|
value.resize(60);
|
||||||
|
@ -383,7 +383,11 @@ static int builtin_set( parser_t &parser, wchar_t **argv )
|
||||||
}
|
}
|
||||||
,
|
,
|
||||||
{
|
{
|
||||||
L"universal", no_argument, 0, 'U'
|
L"universal", no_argument, 0, 'U'
|
||||||
|
}
|
||||||
|
,
|
||||||
|
{
|
||||||
|
L"long", no_argument, 0, 'L'
|
||||||
}
|
}
|
||||||
,
|
,
|
||||||
{
|
{
|
||||||
|
@ -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);
|
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 local = 0, global = 0, exportv = 0;
|
||||||
int erase = 0, list = 0, unexport=0;
|
int erase = 0, list = 0, unexport=0;
|
||||||
int universal = 0, query=0;
|
int universal = 0, query=0;
|
||||||
|
bool shorten_ok = true;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Variables used for performing the actual work
|
Variables used for performing the actual work
|
||||||
|
@ -467,6 +471,10 @@ static int builtin_set( parser_t &parser, wchar_t **argv )
|
||||||
case 'U':
|
case 'U':
|
||||||
universal = 1;
|
universal = 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'L':
|
||||||
|
shorten_ok = false;
|
||||||
|
break;
|
||||||
|
|
||||||
case 'q':
|
case 'q':
|
||||||
query = 1;
|
query = 1;
|
||||||
|
@ -574,8 +582,6 @@ static int builtin_set( parser_t &parser, wchar_t **argv )
|
||||||
wcstring_list_t result;
|
wcstring_list_t result;
|
||||||
size_t j;
|
size_t j;
|
||||||
|
|
||||||
// al_init( &result );
|
|
||||||
// al_init( &indexes );
|
|
||||||
env_var_t dest_str = env_get_string(dest);
|
env_var_t dest_str = env_get_string(dest);
|
||||||
if (! dest_str.missing())
|
if (! dest_str.missing())
|
||||||
tokenize_variable_array( dest_str, result );
|
tokenize_variable_array( dest_str, result );
|
||||||
|
@ -612,7 +618,7 @@ static int builtin_set( parser_t &parser, wchar_t **argv )
|
||||||
if( list )
|
if( list )
|
||||||
{
|
{
|
||||||
/* Maybe we should issue an error if there are any other arguments? */
|
/* 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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -633,7 +639,7 @@ static int builtin_set( parser_t &parser, wchar_t **argv )
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
print_variables( 1, 1, scope );
|
print_variables( 1, 1, shorten_ok, scope );
|
||||||
}
|
}
|
||||||
|
|
||||||
return retcode;
|
return retcode;
|
||||||
|
|
|
@ -1969,7 +1969,6 @@ void set_main_thread() {
|
||||||
main_thread_id = pthread_self();
|
main_thread_id = pthread_self();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Notice when we've forked */
|
/* Notice when we've forked */
|
||||||
static pid_t initial_pid;
|
static pid_t initial_pid;
|
||||||
|
|
||||||
|
@ -1987,7 +1986,7 @@ void setup_fork_guards(void) {
|
||||||
initial_pid = getpid();
|
initial_pid = getpid();
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool is_main_thread() {
|
bool is_main_thread() {
|
||||||
assert (main_thread_id != 0);
|
assert (main_thread_id != 0);
|
||||||
return main_thread_id == pthread_self();
|
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().
|
This is our replacement for pthread_main_np().
|
||||||
*/
|
*/
|
||||||
void set_main_thread();
|
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 */
|
/** 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);
|
void setup_fork_guards(void);
|
||||||
|
|
156
env.cpp
156
env.cpp
|
@ -1072,39 +1072,18 @@ const wchar_t *env_var_t::c_str(void) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
env_var_t env_get_string( const wcstring &key )
|
env_var_t env_get_string( const wcstring &key )
|
||||||
{
|
{
|
||||||
scoped_lock lock(env_lock);
|
/* 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())
|
||||||
if( key == L"history" )
|
|
||||||
{
|
{
|
||||||
wcstring result;
|
env_var_t result;
|
||||||
const wchar_t *current;
|
|
||||||
int i;
|
|
||||||
int add_current=0;
|
|
||||||
|
|
||||||
current = reader_get_buffer();
|
|
||||||
if( current && wcslen( current ) )
|
|
||||||
{
|
|
||||||
add_current=1;
|
|
||||||
result += current;
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
history_t *history = reader_get_history();
|
||||||
|
if (! history) {
|
||||||
|
history = &history_t::history_with_name(L"fish");
|
||||||
|
}
|
||||||
|
if (history)
|
||||||
|
history->get_string_representation(result, ARRAY_SEP_STR);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
else if( key == L"COLUMNS" )
|
else if( key == L"COLUMNS" )
|
||||||
|
@ -1125,6 +1104,8 @@ env_var_t env_get_string( const wcstring &key )
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
||||||
|
scoped_lock lock(env_lock);
|
||||||
|
|
||||||
var_entry_t *res;
|
var_entry_t *res;
|
||||||
env_node_t *env = top;
|
env_node_t *env = top;
|
||||||
wchar_t *item;
|
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 )
|
int env_exist( const wchar_t *key, int mode )
|
||||||
{
|
{
|
||||||
var_entry_t *res;
|
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));
|
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) {
|
history_item_t history_t::item_at_index(size_t idx) {
|
||||||
scoped_lock locker(lock);
|
scoped_lock locker(lock);
|
||||||
|
|
||||||
|
|
|
@ -147,6 +147,9 @@ public:
|
||||||
/** Irreversibly clears history */
|
/** Irreversibly clears history */
|
||||||
void clear();
|
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.) */
|
/** 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);
|
history_item_t item_at_index(size_t idx);
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue