mirror of
https://github.com/fish-shell/fish-shell.git
synced 2025-02-22 09:07:58 +08:00
Adopt tnode in reader_expand_abbreviation_in_command
This commit is contained in:
parent
3d4dd4abef
commit
cfe355554c
@ -18,6 +18,8 @@ using production_element_t = uint8_t;
|
|||||||
// Define primitive types.
|
// Define primitive types.
|
||||||
template <enum parse_token_type_t Token>
|
template <enum parse_token_type_t Token>
|
||||||
struct primitive {
|
struct primitive {
|
||||||
|
using type_tuple = std::tuple<>;
|
||||||
|
static constexpr parse_token_type_t token = Token;
|
||||||
static constexpr production_element_t element() { return Token; }
|
static constexpr production_element_t element() { return Token; }
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -30,6 +32,7 @@ using tok_redirection = primitive<parse_token_type_redirection>;
|
|||||||
// Define keyword types.
|
// Define keyword types.
|
||||||
template <parse_keyword_t Keyword>
|
template <parse_keyword_t Keyword>
|
||||||
struct keyword {
|
struct keyword {
|
||||||
|
using type_tuple = std::tuple<>;
|
||||||
static constexpr production_element_t element() {
|
static constexpr production_element_t element() {
|
||||||
// Convert a parse_keyword_t enum to a production_element_t enum.
|
// Convert a parse_keyword_t enum to a production_element_t enum.
|
||||||
return Keyword + LAST_TOKEN_OR_SYMBOL + 1;
|
return Keyword + LAST_TOKEN_OR_SYMBOL + 1;
|
||||||
@ -106,7 +109,8 @@ struct alternative {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Following are the grammar productions.
|
// Following are the grammar productions.
|
||||||
#define BODY(T) static constexpr parse_token_type_t symbol = symbol_##T;
|
#define BODY(T) static constexpr parse_token_type_t token = symbol_##T;
|
||||||
|
|
||||||
#define DEF(T) struct T : public
|
#define DEF(T) struct T : public
|
||||||
|
|
||||||
#define DEF_ALT(T) struct T : public alternative
|
#define DEF_ALT(T) struct T : public alternative
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
#include "maybe.h"
|
||||||
#include "parse_constants.h"
|
#include "parse_constants.h"
|
||||||
#include "parse_grammar.h"
|
#include "parse_grammar.h"
|
||||||
#include "tokenizer.h"
|
#include "tokenizer.h"
|
||||||
@ -228,6 +229,11 @@ class parse_node_tree_t : public std::vector<parse_node_t> {
|
|||||||
bool job_should_be_backgrounded(const parse_node_t &job) const;
|
bool job_should_be_backgrounded(const parse_node_t &job) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct source_range_t {
|
||||||
|
uint32_t start;
|
||||||
|
uint32_t length;
|
||||||
|
};
|
||||||
|
|
||||||
/// A helper for type-safe manipulation of parse nodes.
|
/// A helper for type-safe manipulation of parse nodes.
|
||||||
/// This is a lightweight value-type class.
|
/// This is a lightweight value-type class.
|
||||||
template <typename Type>
|
template <typename Type>
|
||||||
@ -247,7 +253,7 @@ class tnode_t {
|
|||||||
|
|
||||||
tnode_t(const parse_node_tree_t *t, const parse_node_t *n) : tree(t), nodeptr(n) {
|
tnode_t(const parse_node_tree_t *t, const parse_node_t *n) : tree(t), nodeptr(n) {
|
||||||
assert(t && "tree cannot be null in this constructor");
|
assert(t && "tree cannot be null in this constructor");
|
||||||
assert((!n || n->type == Type::symbol) && "node has wrong type");
|
assert((!n || n->type == Type::token) && "node has wrong type");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the underlying (type-erased) node.
|
/// Return the underlying (type-erased) node.
|
||||||
@ -256,12 +262,24 @@ class tnode_t {
|
|||||||
/// Check whether we're populated.
|
/// Check whether we're populated.
|
||||||
explicit operator bool() const { return nodeptr != nullptr; }
|
explicit operator bool() const { return nodeptr != nullptr; }
|
||||||
|
|
||||||
|
bool has_source() const { return nodeptr && nodeptr->has_source(); }
|
||||||
|
|
||||||
|
maybe_t<source_range_t> source_range() const {
|
||||||
|
if (!has_source()) return none();
|
||||||
|
return source_range_t{nodeptr->source_start, nodeptr->source_length};
|
||||||
|
}
|
||||||
|
|
||||||
|
wcstring get_source(const wcstring &str) const {
|
||||||
|
assert(has_source() && "Source missing");
|
||||||
|
return nodeptr->get_source(str);
|
||||||
|
}
|
||||||
|
|
||||||
/// Type-safe access to a child at the given index.
|
/// Type-safe access to a child at the given index.
|
||||||
template <node_offset_t Index>
|
template <node_offset_t Index>
|
||||||
tnode_t<child_at<Type, Index>> child() const {
|
tnode_t<child_at<Type, Index>> child() const {
|
||||||
using child_type = child_at<Type, Index>;
|
using child_type = child_at<Type, Index>;
|
||||||
const parse_node_t *child = nullptr;
|
const parse_node_t *child = nullptr;
|
||||||
if (nodeptr) child = tree->get_child(*nodeptr, Index, child_type::symbol);
|
if (nodeptr) child = tree->get_child(*nodeptr, Index, child_type::token);
|
||||||
return tnode_t<child_type>{tree, child};
|
return tnode_t<child_type>{tree, child};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -580,7 +580,8 @@ bool reader_expand_abbreviation_in_command(const wcstring &cmdline, size_t curso
|
|||||||
&parse_tree, NULL);
|
&parse_tree, NULL);
|
||||||
|
|
||||||
// Look for plain statements where the cursor is at the end of the command.
|
// Look for plain statements where the cursor is at the end of the command.
|
||||||
const parse_node_t *matching_cmd_node = NULL;
|
using namespace grammar;
|
||||||
|
tnode_t<tok_string> matching_cmd_node;
|
||||||
const size_t len = parse_tree.size();
|
const size_t len = parse_tree.size();
|
||||||
for (size_t i = 0; i < len; i++) {
|
for (size_t i = 0; i < len; i++) {
|
||||||
const parse_node_t &node = parse_tree.at(i);
|
const parse_node_t &node = parse_tree.at(i);
|
||||||
@ -593,12 +594,15 @@ bool reader_expand_abbreviation_in_command(const wcstring &cmdline, size_t curso
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
// Get the command node. Skip it if we can't or it has no source.
|
// Get the command node. Skip it if we can't or it has no source.
|
||||||
const parse_node_t *cmd_node = parse_tree.get_child(node, 0, parse_token_type_string);
|
tnode_t<plain_statement> statement(&parse_tree, &node);
|
||||||
if (cmd_node == NULL || !cmd_node->has_source()) continue;
|
tnode_t<tok_string> cmd_node = statement.child<0>();
|
||||||
|
|
||||||
|
auto msource = cmd_node.source_range();
|
||||||
|
if (!msource) continue;
|
||||||
|
|
||||||
// Now see if its source range contains our cursor, including at the end.
|
// Now see if its source range contains our cursor, including at the end.
|
||||||
if (subcmd_cursor_pos >= cmd_node->source_start &&
|
if (subcmd_cursor_pos >= msource->start &&
|
||||||
subcmd_cursor_pos <= cmd_node->source_start + cmd_node->source_length) {
|
subcmd_cursor_pos <= msource->start + msource->length) {
|
||||||
// Success!
|
// Success!
|
||||||
matching_cmd_node = cmd_node;
|
matching_cmd_node = cmd_node;
|
||||||
break;
|
break;
|
||||||
@ -607,17 +611,16 @@ bool reader_expand_abbreviation_in_command(const wcstring &cmdline, size_t curso
|
|||||||
|
|
||||||
// Now if we found a command node, expand it.
|
// Now if we found a command node, expand it.
|
||||||
bool result = false;
|
bool result = false;
|
||||||
if (matching_cmd_node != NULL) {
|
if (matching_cmd_node) {
|
||||||
assert(matching_cmd_node->type == parse_token_type_string);
|
const wcstring token = matching_cmd_node.get_source(subcmd);
|
||||||
const wcstring token = matching_cmd_node->get_source(subcmd);
|
|
||||||
wcstring abbreviation;
|
wcstring abbreviation;
|
||||||
if (expand_abbreviation(token, &abbreviation)) {
|
if (expand_abbreviation(token, &abbreviation)) {
|
||||||
// There was an abbreviation! Replace the token in the full command. Maintain the
|
// There was an abbreviation! Replace the token in the full command. Maintain the
|
||||||
// relative position of the cursor.
|
// relative position of the cursor.
|
||||||
if (output != NULL) {
|
if (output != NULL) {
|
||||||
output->assign(cmdline);
|
output->assign(cmdline);
|
||||||
output->replace(subcmd_offset + matching_cmd_node->source_start,
|
source_range_t r = *matching_cmd_node.source_range();
|
||||||
matching_cmd_node->source_length, abbreviation);
|
output->replace(subcmd_offset + r.start, r.length, abbreviation);
|
||||||
}
|
}
|
||||||
result = true;
|
result = true;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user