Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
4d7e805
SI-4830 Add API allowing loading and saving Slash history to file
jeanbaptistelab Jun 25, 2024
3619cce
Rewrite slash_complete, dynamically building a list of completions, t…
jeanbaptistelab Jul 30, 2024
458ed6c
0-initialize buffer to remove Valgrind warning
jeanbaptistelab Aug 1, 2024
8aef176
Remove unneeded new line print when calling unique completion's compl…
jeanbaptistelab Aug 16, 2024
2dbb3ea
Restore completion functionality for "help" or "watch" commands
jeanbaptistelab Aug 19, 2024
0802b77
Fix conditional jump or move dependant on uninitialised value
kivkiv12345 Aug 19, 2024
d4669a7
SI-4831 handle multiple trailing blank spaces, make "complete while a…
jeanbaptistelab Sep 4, 2024
ff4a5c6
SI-4598 actually store "help" parameter in data structure
jeanbaptistelab Mar 18, 2024
e4f8e72
Add "help" member to slash_command struct, missed in previous commit
jeanbaptistelab Mar 18, 2024
19214fd
Add new optparse_new_ex(), handling optional help text
jeanbaptistelab Sep 6, 2024
5c087dd
Print extended help if available in slash_command_usage
jeanbaptistelab Sep 6, 2024
4551c74
Let watch command run every X ms,
troelsjessen Aug 23, 2024
e77e235
Initialize complete_in_completion in slash_create() too
jeanbaptistelab Sep 6, 2024
70d0be2
Feed argv/argc into autocompleter
troelsjessen Sep 9, 2024
75ec339
Fix typo in comment
jeanbaptistelab Sep 10, 2024
92b662c
Fix a NULL dereference found while testing get/set param completion
jeanbaptistelab Sep 10, 2024
1fa566b
Fix greedy comparison which prevents option values to be whitespace s…
jeanbaptistelab Sep 10, 2024
dddc6a2
Skip the found command name when building the command line
jeanbaptistelab Sep 10, 2024
8c8b1de
Feature/add-environment-variables-handling (#13)
jeanbaptistelab Sep 13, 2024
ba55621
Refactoring in general completion code removed initial newline when m…
jeanbaptistelab Sep 16, 2024
dc98b77
Actually find an exact match, as per comment. Current code finds a *p…
jeanbaptistelab Sep 20, 2024
7cbffcf
Fix comment
jeanbaptistelab Sep 20, 2024
4754166
Defer signals to external handler
johandc Sep 24, 2024
8f9e8d0
Add indication to know if slash is currently executing a command
troelsjessen Oct 8, 2024
4e50e0a
sigint: if slash busy set slash signal else reset and refresh slash p…
edvardxyz Oct 8, 2024
6e59427
Fix strncpy() length from source, rather than destination
kivkiv12345 Oct 15, 2024
0eabe69
fix: when one and only completion is found, replace the (potentially)…
jeanbaptistelab Oct 24, 2024
6ea6960
Prevent crash when passing no value to short options that require one
jeanbaptistelab Nov 5, 2024
31926bd
PLT-291 Added customizable hooks to slash_run()
kivkiv12345 Dec 8, 2024
337b3c8
Added description of __FILE__ and __FILE_DIR__ environment variables
kivkiv12345 Dec 11, 2024
8c4eb8a
Improve cmd_run() documentation
kivkiv12345 Dec 20, 2024
5e6439d
Bump slash commands maximum number of allowed arguments to 32
jeanbaptistelab Dec 20, 2024
4799fc2
Added verbosity argument to "run"
kivkiv12345 Feb 27, 2025
37a0d6a
Comments are indicated by '#' character, update code to actually use …
jeanbaptistelab Mar 21, 2025
4dda935
Move "node" cmd out of slash and into CSH (where it belongs) to allow…
jeanbaptistelab Mar 28, 2025
338fcc0
Progressive removal of CSH specifics (#18)
jeanbaptistelab Apr 1, 2025
70041ee
Feature/CSH-21-Extend-slash-to-allow-use-of-custom-options-handling (…
jeanbaptistelab Apr 7, 2025
cf6ae96
Lazy fix: there is an "off-by-one" algorithmic error in slash history…
jeanbaptistelab Apr 16, 2025
42e90ed
Handle "HOME" and "END" keys when in a TMUX session
jeanbaptistelab Apr 30, 2025
cdd3707
Fix warnings:
jeanbaptistelab May 7, 2025
f2313b0
Handle memory allocation failures
jeanbaptistelab May 7, 2025
0cfd016
Export a "link whole" meson dependency
jeanbaptistelab May 14, 2025
9db9662
Extend slash API to allow enabling/disabling handling of stdout/stdin…
jeanbaptistelab May 14, 2025
9cdbbbd
Trim trailing whitespaces from stdin-read line
jeanbaptistelab May 28, 2025
c5bdffb
Fix valgrind warning when `slash_trim()`ing empty line
kivkiv12345 Jun 11, 2025
439549a
Better (but not good yet) handling of "~" when tab-completing paths
jeanbaptistelab Jun 26, 2025
49fc78f
Fix parameter to getcwd() call
jeanbaptistelab Jun 30, 2025
1f09360
Fix crash in slash_path_completer
jeanbaptistelab Jul 3, 2025
8221975
Added customizable context pointer to `struct slash_command` (#20)
kivkiv12345 Jul 8, 2025
79e572a
Added `slash_on_execute_post_hook()`
kivkiv12345 Jul 10, 2025
68fef6d
Fix `watch` memory leak
kivkiv12345 Jul 16, 2025
07d7767
Remove `rdp_opt_set()` and `rdp_opt_reset()`
kivkiv12345 Jul 17, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions include/slash/dflopt.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
#pragma once

/* TODO: determine when to enable this */
#if 0
#pragma GCC warning "dflopt.h is deprecated, use #include <apm/csh_api.h> instead"
#endif
#include <slash/slash.h>
#include <slash/optparse.h>

Expand All @@ -15,5 +19,3 @@ extern unsigned int rdp_dfl_ack_timeout;
extern unsigned int rdp_dfl_ack_count;

void rdp_opt_add(optparse_t * parser);
void rdp_opt_set();
void rdp_opt_reset();
45 changes: 45 additions & 0 deletions include/slash/optparse.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,29 @@
typedef struct optparse optparse_t;
typedef struct optparse_opt optparse_opt_t;

/**
* @brief Create a new option parser context, remeber to free it using optparse_del() when done
* @param progname name to be associated with the option parser
* @param arg_summary short list of optional command line options and arguments
* @return pointer to new context, NULL if something went wrong
* @warning the progname and arg_summary arguments, if not NULL, must be valid for the entire lifecycle of the option parser!
*/
optparse_t *optparse_new(const char *progname, const char *arg_summary);

/**
* @brief Create a new options parser context, remeber to free it using optparse_del() when done
* @param progname name to be associated with the option parser
* @param arg_summary short list of optional command line options and arguments, can be NULL if not relevant
* @param help longer description of the command, can be NULL if not relevant.
* @return pointer to new context, NULL if something went wrong
* @warning the progname, arg_summary and help arguments, if not NULL, must be valid for the entire lifecycle of the option parser!
*/
optparse_t *optparse_new_ex(const char *progname, const char *arg_summary, const char *help);

/**
* @brief Release the memory for the given option parser object
* @param parser pointer to valid option parser obtained by calling optparse_new() or optparse_new_ex()
*/
void optparse_del(optparse_t *parser);

int optparse_parse(optparse_t *parser, int argc, const char *argv[]);
Expand All @@ -33,4 +55,27 @@ optparse_opt_t *optparse_add_double(optparse_t *parser, int short_opt, const cha

optparse_opt_t *optparse_add_string(optparse_t *parser, int short_opt, const char *long_opt, const char *arg_desc, char **ptr, char *help);

/**
* @brief interface to be implemented for custom option parsers
*
* This function will be called by the optparse framework when it processes an
* option for which this custom option value function was registered
* @param data an opaque pointer where the parsed option value must be stored
* @param arg the part of the command line containing the option value as a string to be parsed
*/
typedef int (*optparse_custom_func_t)(void *data, const char * arg);

/**
* @brief Register an option with a custom parser (see the "func" param)
* @param parser pointer to valid optparse object the option will be attached to
* @param short_opt single character option (for example: 'c' for the corresponding "-c" cmd line option). Set to '\0' if you do not want a short option
* @param long_opt string option (for example "test" for the corresponding "--test" cmd line option). Set to NULL if you do not want a long option
* @param arg_desc string describing the argument (will be shown when help is invoked), may be NULL
* @param help string describing waht this option is/does
* @param func ptr to a cutom option value parser, see the optparse_custom_func_t typedef documentation
* @param data opaque pointer to a valid memory where the "func" above will store the parsed option value
* @return reference to newly created optparse_opt_t object
*/
optparse_opt_t *optparse_add_custom(optparse_t * parser, int short_opt, const char * long_opt, const char * arg_desc, const char * help, optparse_custom_func_t func, void * data);

#endif /* _OPTPARSE_H */
89 changes: 85 additions & 4 deletions include/slash/slash.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@

#include <stddef.h>
#include <stdbool.h>
#include <stdio.h>

#include <slash_config.h>

Expand Down Expand Up @@ -60,6 +61,7 @@
.func = _func,\
.completer = _completer,\
.args = _args,\
.help = _help, \
.next = {NULL}, /* Next pointer in case the user wants to implement custom ordering within or across APMs.
It should not required by the default implementation. */\
};
Expand Down Expand Up @@ -96,6 +98,7 @@
/* Command prototype */
struct slash;
typedef int (*slash_func_t)(struct slash *slash);
typedef int (*slash_func_context_t)(struct slash *slash, void *context);

/* Wait function prototype,
* this function is implemented by user, so use a void* instead of struct slash* */
Expand All @@ -119,14 +122,24 @@ typedef void (*slash_completer_func_t)(struct slash *slash, char * token);
struct slash_command {
/* Static data */
char *name;
const slash_func_t func;
union {
/* Traditional function used by the `slash_command()` macros. */
const slash_func_t func;
/* Function with context pointer, for advanced API usage. */
const slash_func_context_t func_ctx;
};
const char *args;
const char *help;
const slash_completer_func_t completer;
/* Next pointer in case the user wants to implement custom ordering within or across APMs.
It should not required by the default implementation. */
/* single linked list:
* The weird definition format comes from sys/queue.h SLINST_ENTRY() macro */
struct { struct slash_command *sle_next; } next;

/* Optional context pointer (after `next` for ABI compatibility).
Will be supplied to `func_ctx` if specified. */
void *context;
};

/* Slash context */
Expand All @@ -140,6 +153,8 @@ struct slash {
int fd_read;
slash_waitfunc_t waitfunc;
bool use_activate;
int signal;
int busy;

/* Line editing */
size_t line_size;
Expand All @@ -161,7 +176,7 @@ struct slash {
char *history_head;
char *history_tail;
char *history_cursor;

FILE *history_file;
/* Command interface */
char **argv;
int argc;
Expand All @@ -176,8 +191,12 @@ struct slash {
/* Command list */
struct slash_command * cmd_list;

/* Completions */
bool in_completion;
/* Allow calling complete functions while already in in one of those functions.
* Use case: when completing "help", you only want to complete the *name* of commands to get help for
* BUT while completing "watch" (or watch-like commands), you want to carry on completing as much as possible,
* for instance, typing: "w<TAB>g<TAB>s<TAB>" would result in the completed command line "watch get serial0" in 6 keystrokes
*/
bool complete_in_completion;
};

/**
Expand All @@ -195,13 +214,53 @@ void slash_destroy(struct slash *slash);

char *slash_readline(struct slash *slash);

void slash_sigint(struct slash *slash, int signum);

/**
* @brief Implement this function to do something with the current line (logging, etc)
*
* @param line the slash line about to be executed
*/
void slash_on_execute_hook(const char *line);

/**
* @param line the slash line which was just executed
*/
void slash_on_execute_post_hook(const char *line, struct slash_command *command);

/**
* @brief Will be called before a file is executed by "run <file>", implement it to set environment variables for example.
*
* @param filename name of the file to be executed.
* @param ctx_for_post Assignable context pointer which will be passed to the corresponding post_hook call. If it is malloc, it should be freed in the post-hook.
*/
void slash_on_run_pre_hook(const char * const filename, void ** ctx_for_post);

/**
* @brief Will be called after a file has been executed by "run <file>", implement it to set clear variables for example.
*
* @param filename name of the file which was executed.
* @param ctx customizable context from corresponding pre-hook.
*/
void slash_on_run_post_hook(const char * const filename, void * ctx);


typedef char *(*slash_process_cmd_line_hook_t)(const char *line);
/**
* @brief Set this variable to a function if you wish to modify the command line about to be executed
*
* @param line the slash line about to be executed
* @return a malloc'ed pointer to the processed command line, this will be free()'d for you, NULL is a valid
* return value and will cause the original line to be used as-is.
*/
extern slash_process_cmd_line_hook_t slash_process_cmd_line_hook;

/**
* @brief Set this variable to a function if you wish to execute general completions after specific completions have been executed
* @see slash_completer_func_t
*/
extern slash_completer_func_t slash_global_completer;

int slash_execute(struct slash *slash, char *line);

int slash_loop(struct slash *slash);
Expand Down Expand Up @@ -239,6 +298,13 @@ void slash_command_description(struct slash *slash, struct slash_command *comman

int slash_run(struct slash *slash, char * filename, int printcmd);

/**
* @brief Populate Slash history buffer with the content of the given file
* @param slash pointer to valid slash context
* @param history_filename filename to use (will be created if it doesn't exist) to read and write history
*/
void slash_init_history_from_file(struct slash *slash, const char *history_filename);

void slash_history_add(struct slash *slash, char *line);

typedef struct slash_list_iterator_s {
Expand All @@ -251,4 +317,19 @@ int slash_list_add(struct slash_command * item);
int slash_list_remove(const struct slash_command * item);
int slash_list_init();

/**
* @brief let slash handle stdout/stdin
* @param slash pointer to valid slash instance
*/
void slash_acquire_std_in_out(struct slash *slash);

/**
* @brief let slash release handling of stdout/stdin to default. Use this function if you have for instance an APM that needs stdin/stdout control
* @warning remember to call slash_acquire_std_in_out when you are done!
* @param slash pointer to valid slash instance
* @return 0 if success, -ENOTTY in case of failure
*/
void slash_release_std_in_out(struct slash *slash);


#endif /* _SLASH_H_ */
8 changes: 6 additions & 2 deletions meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ slash_sources = files([
if get_option('builtins')
slash_sources += files([
'src/builtins.c',
'src/dflopt.c',
'src/run.c',
])
endif
Expand Down Expand Up @@ -40,9 +39,14 @@ slash_lib = library('slash',
dependencies : dependencies,
install : false,
)

slash_dep = declare_dependency(
include_directories : slash_inc,
link_with : slash_lib,
)

slash_link_whole_dep = declare_dependency(
include_directories : slash_inc,
link_with : slash_lib,
link_whole: [slash_lib]
)
18 changes: 15 additions & 3 deletions src/builtins.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <time.h>

#include <slash/slash.h>
#include <slash/dflopt.h>
#include <slash/optparse.h>
#include <slash/completer.h>

Expand Down Expand Up @@ -99,7 +99,7 @@ slash_command(confirm, slash_builtin_confirm, "", "Block until user confirmation
static int slash_builtin_watch(struct slash *slash)
{

unsigned int interval = slash_dfl_timeout;
unsigned int interval = 1000;
unsigned int count = 0;

optparse_t * parser = optparse_new("watch", "<command...>");
Expand Down Expand Up @@ -130,19 +130,31 @@ static int slash_builtin_watch(struct slash *slash)
char cmd_exec[slash->line_size];
strncpy(cmd_exec, line, slash->line_size);

/* Read time it takes to execute command */
struct timespec time_before, time_after;
clock_gettime(CLOCK_MONOTONIC, &time_before);

/* Execute command */
slash_execute(slash, cmd_exec);

clock_gettime(CLOCK_MONOTONIC, &time_after);

if ((count > 0) && (count-- == 1)) {
break;
}

/* Calculate remaining time to ensure execution is running no more often than what interval dictates */
unsigned int elapsed = (time_after.tv_sec-time_before.tv_sec)*1000 + (time_after.tv_nsec-time_before.tv_nsec)/1000000;
unsigned int remaining = 0;
if (interval > elapsed) remaining = interval - elapsed;

/* Delay (press enter to exit) */
if (slash_wait_interruptible(slash, interval) != 0)
if (slash_wait_interruptible(slash, remaining) != 0)
break;

}

optparse_del(parser);
return SLASH_SUCCESS;
}
slash_command_completer(watch, slash_builtin_watch, slash_watch_completer, "<command...>", "Repeat a command")
5 changes: 5 additions & 0 deletions src/builtins.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,17 @@

#include <sys/types.h>

/* Configuration */
#define SLASH_ARG_MAX 32 /* Maximum number of arguments */
#define SLASH_SHOW_MAX 25 /* Maximum number of commands to list */

/* Declarations for required implementation functions in slash.c */
void slash_command_usage(struct slash *slash, struct slash_command *command);
char *slash_history_increment(struct slash *slash, char *ptr);
int slash_putchar(struct slash *slash, char c);
struct slash_command * slash_command_find(struct slash *slash, char *line, size_t linelen, char **args);
void slash_command_description(struct slash *slash, struct slash_command *command);
int slash_build_args(char *args, char **argv, int *argc);

/* Define and initialize section variables */
/* __attribute__((visibility("hidden"))) prevents the section symbols from linking with
Expand Down
Loading