Skip to content

Commit

Permalink
Implement query_inverting_delimiter
Browse files Browse the repository at this point in the history
When enabled, a query-inverting delimiter can be used to refine earlier
parts of a query. See the README for details.
  • Loading branch information
nixprime committed Jun 6, 2015
1 parent a3bb678 commit 09cdf5d
Show file tree
Hide file tree
Showing 6 changed files with 84 additions and 20 deletions.
31 changes: 20 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,11 +75,14 @@ Installation
Options
-------

- To control how matched characters are highlighted, set
All of the following options are set by adding

let g:cpsm_highlight_mode = (highlight mode)
let (option name) = (option value)

Valid highlight modes are:
to your .vimrc.

- `g:cpsm_highlight_mode` controls how matches are highlighted. Valid highlight
modes are:

- "none": Do not highlight any match characters.

Expand All @@ -93,19 +96,25 @@ Options

- By default, cpsm will automatically detect the number of matcher threads
based on the available hardware concurrency. To limit the number of threads
that cpsm can use, add
that cpsm can use, set `g:cpsm_max_threads`.

- When `g:cpsm_query_inverting_delimiter` is set to a single character, it can
be used in a query to move the part of the query after it to the part of the
query before it. For example, if `g:cpsm_query_inverting_delimiter` is a
space, then:

let g:cpsm_max_threads = (maximum number of threads)
- A query of "foo" is matched normally.

to your .vimrc.
- A query of "foo bar" is matched as if it were "barfoo".

- To enable Unicode support, add
- A query of "foo bar qux" is matched as if it were "quxbarfoo".

let g:cpsm_unicode = 1
If `g:cpsm_query_inverting_delimiter` is unset or empty, this feature is
disabled.

to your .vimrc. Unicode support is currently very limited, and consists
mostly of parsing input strings as UTF-8 and handling the case of non-ASCII
letters correctly.
- To enable Unicode support, set `g:cpsm_unicode` to 1. Unicode support is
currently very limited, and consists mostly of parsing input strings as UTF-8
and handling the case of non-ASCII letters correctly.

Performance
-----------
Expand Down
5 changes: 3 additions & 2 deletions autoload/cpsm.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,10 @@ def ctrlp_match():
vim.eval("a:items"), vim.eval("a:str"),
limit=int(vim.eval("a:limit")), mmode=vim.eval("a:mmode"),
ispath=int(vim.eval("a:ispath")), crfile=vim.eval("a:crfile"),
highlight_mode=vim.eval("g:cpsm_highlight_mode"),
max_threads=int(vim.eval("g:cpsm_max_threads")),
unicode=int(vim.eval("g:cpsm_unicode")),
highlight_mode=vim.eval("g:cpsm_highlight_mode"))
query_inverting_delimiter=vim.eval("g:cpsm_query_inverting_delimiter"),
unicode=int(vim.eval("g:cpsm_unicode")))
# Escape backslashes and ".
vim.command("let s:results = [%s]" % ",".join(
map(_escape_and_quote, results)))
Expand Down
3 changes: 3 additions & 0 deletions autoload/cpsm.vim
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ endif
if !exists('g:cpsm_max_threads')
let g:cpsm_max_threads = 0
endif
if !exists('g:cpsm_query_inverting_delimiter')
let g:cpsm_query_inverting_delimiter = ''
endif
if !exists('g:cpsm_unicode')
let g:cpsm_unicode = 0
endif
Expand Down
32 changes: 25 additions & 7 deletions src/python_extension_main.cc
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include <string>
#include <utility>

#include <boost/range/adaptor/reversed.hpp>
#include <boost/utility/string_ref.hpp>

#include "ctrlp_util.h"
Expand Down Expand Up @@ -97,27 +98,33 @@ extern "C" {
static PyObject* cpsm_ctrlp_match(PyObject* self, PyObject* args,
PyObject* kwargs) {
static char const* kwlist[] = {
"items", "query", "limit", "mmode", "ispath",
"crfile", "max_threads", "unicode", "highlight_mode", nullptr};
"items", "query", "limit", "mmode", "ispath", "crfile", "highlight_mode",
"max_threads", "query_inverting_delimiter", "unicode", nullptr};
// Required parameters.
PyObject* items_obj;
char const* query_data;
Py_ssize_t query_size;
// CtrlP-provided options.
int limit_int = -1;
char const* mmode_data = nullptr;
Py_ssize_t mmode_size = 0;
int is_path = 0;
char const* cur_file_data = nullptr;
Py_ssize_t cur_file_size = 0;
int max_threads_int = 0;
int unicode = 0;
// cpsm-specific options.
char const* highlight_mode_data = nullptr;
Py_ssize_t highlight_mode_size = 0;
int max_threads_int = 0;
char const* query_inverting_delimiter_data = nullptr;
Py_ssize_t query_inverting_delimiter_size = 0;
int unicode = 0;
if (!PyArg_ParseTupleAndKeywords(
args, kwargs, "Os#|is#is#iis#", const_cast<char**>(kwlist),
args, kwargs, "Os#|is#is#s#is#i", const_cast<char**>(kwlist),
&items_obj, &query_data, &query_size, &limit_int, &mmode_data,
&mmode_size, &is_path, &cur_file_data, &cur_file_size,
&max_threads_int, &unicode, &highlight_mode_data,
&highlight_mode_size)) {
&highlight_mode_data, &highlight_mode_size, &max_threads_int,
&query_inverting_delimiter_data, &query_inverting_delimiter_size,
&unicode)) {
return nullptr;
}

Expand All @@ -129,6 +136,17 @@ static PyObject* cpsm_ctrlp_match(PyObject* self, PyObject* args,

try {
std::string query(query_data, query_size);
boost::string_ref query_inverting_delimiter(query_inverting_delimiter_data,
query_inverting_delimiter_size);
if (!query_inverting_delimiter.empty()) {
if (query_inverting_delimiter.size() > 1) {
throw Error("query inverting delimiter must be a single character");
}
query = str_join(boost::adaptors::reverse(
str_split(query, query_inverting_delimiter[0])),
"");
}

MatcherOpts mopts;
mopts.cur_file = std::string(cur_file_data, cur_file_size);
mopts.is_path = is_path;
Expand Down
16 changes: 16 additions & 0 deletions src/str_util.cc
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,22 @@ void decode_utf8_string(boost::string_ref str, std::vector<char32_t>& chars,

} // namespace

std::vector<boost::string_ref> str_split(boost::string_ref str,
char const delimiter) {
std::vector<boost::string_ref> splits;
while (true) {
auto const dpos = str.find_first_of(delimiter);
if (dpos == boost::string_ref::npos) {
break;
}
splits.push_back(str.substr(0, dpos));
str.remove_prefix(dpos+1);
}
splits.push_back(str);
return splits;
}


StringHandler::StringHandler(StringHandlerOpts opts) : opts_(std::move(opts)) {
#if !CPSM_CONFIG_ICU
if (opts_.unicode) {
Expand Down
17 changes: 17 additions & 0 deletions src/str_util.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,23 @@ std::string str_cat(Args... args) {
return ss.str();
}

// Splits a string into substrings separated by a delimiter.
std::vector<boost::string_ref> str_split(boost::string_ref str,
char const delimiter);

// Joins an iterable over a type that can be stringified through a stringstream
// with the given separator.
template <typename T>
std::string str_join(T const& xs, boost::string_ref const sep) {
std::stringstream ss;
boost::string_ref s;
for (auto const& x : xs) {
ss << s << x;
s = sep;
}
return ss.str();
}

// Exception type used by this package.
class Error : public std::exception {
public:
Expand Down

0 comments on commit 09cdf5d

Please sign in to comment.