diff --git a/tools/lammps-shell/lammps-shell.cpp b/tools/lammps-shell/lammps-shell.cpp index 1ae548e4f5..3dd80482d2 100644 --- a/tools/lammps-shell/lammps-shell.cpp +++ b/tools/lammps-shell/lammps-shell.cpp @@ -52,6 +52,9 @@ const char *lmp_style[] = {"atom", "integrate", "minimize", "pair", "bond", "angle", "dihedral", "improper", "kspace", "fix", "compute", "region", "dump"}; +enum { COMPUTE_ID, DUMP_ID, FIX_ID, MOLECULE_ID, REGION_ID, VARIABLE_ID }; +const char *lmp_id[] = {"compute", "dump", "fix", "molecule", "region", "variable"}; + std::vector commands; // this list of commands is generated by: @@ -152,6 +155,46 @@ template char *style_generator(const char *text, int state) return nullptr; } +template char *id_generator(const char *text, int state) +{ + static int idx, num, len; + if (!state) { + idx = 0; + num = lammps_id_count(lmp, lmp_id[ID]); + len = strlen(text); + } + + while (idx < num) { + lammps_id_name(lmp, lmp_id[ID], idx, buf, buflen); + ++idx; + if ((len == 0) || (strncmp(text, buf, len) == 0)) return dupstring(buf); + } + return nullptr; +} + +template char *ref_generator(const char *text, int state) +{ + char prefix[] = "X_"; + prefix[0] = PREFIX; + + if (strncmp(text, prefix, 2) == 0) { + char *id = id_generator(text + 2, state); + char *ref = nullptr; + if (id) { + ref = (char *)malloc(strlen(id) + 3); + if (ref) { + ref[0] = PREFIX; + ref[1] = '_'; + ref[2] = 0; + strcat(ref, id); + } + free(id); + } + return ref; + } + return nullptr; +} + extern "C" { static char *cmd_generator(const char *text, int state) { @@ -168,6 +211,57 @@ static char *cmd_generator(const char *text, int state) return nullptr; } +static char *compute_id_generator(const char *text, int state) +{ + return id_generator(text, state); +} + +static char *compute_ref_generator(const char *text, int state) +{ + return ref_generator(text, state); +} + +static char *dump_id_generator(const char *text, int state) +{ + return id_generator(text, state); +} + +static char *fix_id_generator(const char *text, int state) +{ + return id_generator(text, state); +} + +static char *fix_ref_generator(const char *text, int state) +{ + return ref_generator(text, state); +} + +static char *variable_ref_generator(const char *text, int state) +{ + return ref_generator(text, state); +} + +static char *variable_expand_generator(const char *text, int state) +{ + if (strncmp(text, "${", 2) == 0) { + char *id = id_generator(text + 2, state); + char *ref = nullptr; + if (id) { + ref = (char *)malloc(strlen(id) + 4); + if (ref) { + ref[0] = '$'; + ref[1] = '{'; + ref[2] = 0; + strcat(ref, id); + strcat(ref, "}"); + } + free(id); + } + return ref; + } + return nullptr; +} + static char *atom_generator(const char *text, int state) { return style_generator(text, state); @@ -262,10 +356,18 @@ static char **cmd_completion(const char *text, int start, int) matches = rl_completion_matches(text, cmd_generator); } else { // try to provide context specific matches - // first split the already completed text + // first split the already completed text into words for position specific expansion auto words = utils::split_words(std::string(rl_line_buffer).substr(0, start)); - if (words.size() == 1) { // expand second word + if (strncmp(text, "c_", 2) == 0) { // expand references to computes or fixes + matches = rl_completion_matches(text, compute_ref_generator); + } else if (strncmp(text, "f_", 2) == 0) { + matches = rl_completion_matches(text, fix_ref_generator); + } else if (strncmp(text, "v_", 2) == 0) { + matches = rl_completion_matches(text, variable_ref_generator); + } else if (strncmp(text, "${", 2) == 0) { + matches = rl_completion_matches(text, variable_expand_generator); + } else if (words.size() == 1) { // expand second word if (words[0] == "atom_style") { matches = rl_completion_matches(text, atom_generator); } else if (words[0] == "pair_style") { @@ -284,6 +386,12 @@ static char **cmd_completion(const char *text, int start, int) matches = rl_completion_matches(text, integrate_generator); } else if (words[0] == "min_style") { matches = rl_completion_matches(text, minimize_generator); + } else if (words[0] == "compute_modify") { + matches = rl_completion_matches(text, compute_id_generator); + } else if (words[0] == "dump_modify") { + matches = rl_completion_matches(text, dump_id_generator); + } else if (words[0] == "fix_modify") { + matches = rl_completion_matches(text, fix_id_generator); } } else if (words.size() == 2) { // expand third word @@ -431,6 +539,7 @@ int main(int argc, char **argv) char *line; std::string trimmed; + std::cout << "LAMMPS Shell version 1.0\n"; lmp = lammps_open_no_mpi(argc, argv, nullptr); if (lmp == nullptr) return 1;