Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
nixprime committed Apr 26, 2015
0 parents commit a8edbd1
Show file tree
Hide file tree
Showing 18 changed files with 1,032 additions and 0 deletions.
65 changes: 65 additions & 0 deletions .clang-format
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
---
Language: Cpp
# BasedOnStyle: Google
AccessModifierOffset: -1
AlignAfterOpenBracket: true
AlignEscapedNewlinesLeft: true
AlignOperands: true
AlignTrailingComments: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortBlocksOnASingleLine: false
AllowShortCaseLabelsOnASingleLine: false
AllowShortIfStatementsOnASingleLine: true
AllowShortLoopsOnASingleLine: true
AllowShortFunctionsOnASingleLine: All
AlwaysBreakAfterDefinitionReturnType: false
AlwaysBreakTemplateDeclarations: true
AlwaysBreakBeforeMultilineStrings: true
BreakBeforeBinaryOperators: None
BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: false
BinPackParameters: true
BinPackArguments: true
ColumnLimit: 80
ConstructorInitializerAllOnOneLineOrOnePerLine: true
ConstructorInitializerIndentWidth: 4
DerivePointerAlignment: true
ExperimentalAutoDetectBinPacking: false
IndentCaseLabels: true
IndentWrappedFunctionNames: false
IndentFunctionDeclarationAfterType: false
MaxEmptyLinesToKeep: 1
KeepEmptyLinesAtTheStartOfBlocks: false
NamespaceIndentation: None
ObjCBlockIndentWidth: 2
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: false
PenaltyBreakBeforeFirstCallParameter: 1
PenaltyBreakComment: 300
PenaltyBreakString: 1000
PenaltyBreakFirstLessLess: 120
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 200
PointerAlignment: Left
SpacesBeforeTrailingComments: 2
Cpp11BracedListStyle: true
Standard: Auto
IndentWidth: 2
TabWidth: 8
UseTab: Never
BreakBeforeBraces: Attach
SpacesInParentheses: false
SpacesInSquareBrackets: false
SpacesInAngles: false
SpaceInEmptyParentheses: false
SpacesInCStyleCastParentheses: false
SpaceAfterCStyleCast: false
SpacesInContainerLiterals: true
SpaceBeforeAssignmentOperators: true
ContinuationIndentWidth: 4
CommentPragmas: '^ IWYU pragma:'
ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ]
SpaceBeforeParens: ControlStatements
DisableFormat: false
...

9 changes: 9 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Vim
*[._]s[a-w][a-z]

# C/C++
*.o
*.so

# Python
*.py[cod]
76 changes: 76 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
cpsm
====

cpsm is a matcher for [CtrlP][], specialized for paths.

Requirements
------------

- Vim 7.4, compiled with the `+python` flag.

- Python headers (Ubuntu: package `python-dev`).

- A C++ compiler supporting C++11.

- Boost headers (Ubuntu: package `libboost-all-dev`).

Installation
------------

1. Install cpsm using your favorite Vim package manager. For example, with
[Vundle](http://github.com/gmarik/Vundle.vim), this consists of adding:

Vundle 'nixprime/cpsm'

to your `vimrc` and then running `:PluginInstall` from Vim.

2. Build the Python module. On Linux, `cd` into `~/.vim/bundle/cpsm` and run
`./install.sh`. Otherwise, peek inside `install.sh` and see what it does.

3. Add:

let g:ctrlp_match_func = {'match': 'cpsm#CtrlPMatch'}

to your `vimrc`.

Algorithm
---------

As with all CtrlP matchers I know of, cpsm is a subsequence matcher; all
characters in the query must appear in the search key in the same order, though
not necessarily adjacent. The main thing that distinguishes cpsm is its ranking
algorithm for paths.

- Consider the query `foobar` and the matches `baz/foobar.c` and
`foo/baz/bar.c`. For a path search, the user most likely wants the first
result: it is most likely that the user has entered part of the filename. But
left-to-right matching will most likely favor the second result. This implies
that we want to match at least the filename first.

- Consider the query `dfoo.c` and the matches `d/a/b/c/foo.c` and
`d/a/b/d/foo.c`. If path components are matched left-to-right outside of the
filename, then the two results are equivalent. In practice, the leading d is
likely to be a disambiguating directory prefix *closer* to the filename. This
implies that we want to match right-to-left across path components in
general.

- Consider the query `foo` and the matches `foo_bar` and `bar_foo`. It's
likelier that the user entered the beginning of the filename (and wants
`foo_bar`) than that they entered a substring in the middle of the filename
(and wants `bar_foo`). This implies that we value prefixes in path
components, which in turn means that we need to match left-to-right within a
path component.

- Consider the query `readme` and the matches `third_party/foo/README` and
`third_party/bar/README`. Without additional context, these matches are
equivalent. However, if the currently open file is `third_party/foo/foo.h`,
then the former match is more likely to be correct. This implies that we
value "proximity" to the current file.

License
-------

This software is licensed under the [Apache License, Version 2.0][LICENSE].

[CtrlP]: http://github.com/kien/ctrlp.vim
[LICENSE]: http://www.apache.org/licenses/LICENSE-2.0
35 changes: 35 additions & 0 deletions autoload/cpsm.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# cpsm - fuzzy path matcher
# Copyright (C) 2015 Jamie Liu
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import os.path
import sys
import vim

script_dir = vim.eval("s:script_dir")
python_dir = os.path.join(script_dir, "..", "python")
sys.path.append(python_dir)
import cpsm

def ctrlp_match():
# TODO: a:regex is unimplemented.
results = cpsm.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"))
# Escape backslashes and ".
vim.command("let s:results = [%s]" % ",".join(
'"%s"' % r.replace("\\", "\\\\").replace('"', '\\"')
for r in results))
23 changes: 23 additions & 0 deletions autoload/cpsm.vim
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
" cpsm - fuzzy path matcher
" Copyright (C) 2015 Jamie Liu
"
" Licensed under the Apache License, Version 2.0 (the "License");
" you may not use this file except in compliance with the License.
" You may obtain a copy of the License at
"
" http://www.apache.org/licenses/LICENSE-2.0
"
" Unless required by applicable law or agreed to in writing, software
" distributed under the License is distributed on an "AS IS" BASIS,
" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
" See the License for the specific language governing permissions and
" limitations under the License.

let s:script_dir = escape(expand('<sfile>:p:h'), '\')

execute 'pyfile ' . s:script_dir . '/cpsm.py'

function cpsm#CtrlPMatch(items, str, limit, mmode, ispath, crfile, regex)
py ctrlp_match()
return s:results
endfunction
9 changes: 9 additions & 0 deletions install.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#!/bin/bash

set -o errexit
set -o nounset
set -o pipefail

python setup.py build
mkdir -p python/
cp build/lib*/* python/
28 changes: 28 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# cpsm - fuzzy path matcher
# Copyright (C) 2015 Jamie Liu
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from distutils.core import setup, Extension

srcs = [
"src/ctrlp_util.cc",
"src/matcher.cc",
"src/path_util.cc",
"src/python_extension_main.cc",
]

cpsm = Extension("cpsm", sources=srcs, extra_compile_args=["-std=c++11"])

setup(name="cpsm", version="0.1", description="A path matcher.",
ext_modules=[cpsm])
11 changes: 11 additions & 0 deletions src/.ycm_extra_conf.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
def FlagsForFile(filename, **kwargs):
return {
"flags": [
"-x", "c++",
"-std=c++11",
"-I", ".",
"-I", "/usr/include/python2.7",
"-Wall",
],
"do_cache": True,
}
47 changes: 47 additions & 0 deletions src/ctrlp_util.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// cpsm - fuzzy path matcher
// Copyright (C) 2015 Jamie Liu
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "ctrlp_util.h"

#include <stdexcept>

#include "path_util.h"
#include "str_util.h"

namespace cpsm {

std::function<boost::string_ref(boost::string_ref)> match_mode_item_substr_fn(
boost::string_ref mmode) {
if (mmode == "full-line") {
return nullptr;
} else if (mmode == "filename-only") {
return path_basename;
} else if (mmode == "first-non-tab") {
return [](boost::string_ref const x) -> boost::string_ref {
return x.substr(0, x.find_first_of('\t'));
};
} else if (mmode == "until-last-tab") {
return [](boost::string_ref const x) -> boost::string_ref {
auto const pos = x.find_last_of('\t');
if (pos == boost::string_ref::npos) {
return x;
}
return x.substr(pos+1);
};
}
throw std::runtime_error(str_cat("unknown match mode ", mmode));
}

} // namespace cpsm
34 changes: 34 additions & 0 deletions src/ctrlp_util.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// cpsm - fuzzy path matcher
// Copyright (C) 2015 Jamie Liu
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// CtrlP-specific support utilities.

#ifndef CPSM_CTRLP_UTIL_H_
#define CPSM_CTRLP_UTIL_H_

#include <functional>

#include <boost/utility/string_ref.hpp>

namespace cpsm {

// Returns an item substring function (see MatcherOpts::item_substr_fn) for
// the given CtrlP match mode.
std::function<boost::string_ref(boost::string_ref)> match_mode_item_substr_fn(
boost::string_ref mmode);

} // namespace cpsm

#endif /* CPSM_CTRLP_UTIL_H_ */
Loading

0 comments on commit a8edbd1

Please sign in to comment.