mirror of
https://github.com/kovidgoyal/kitty.git
synced 2024-09-11 22:47:45 +03:00
find common prefix and suffix of two strings
This commit is contained in:
parent
866b53f384
commit
be9d876997
@ -6,6 +6,10 @@
|
|||||||
import os
|
import os
|
||||||
import subprocess
|
import subprocess
|
||||||
|
|
||||||
|
from .collect import lines_for_path
|
||||||
|
|
||||||
|
left_lines = right_lines = None
|
||||||
|
|
||||||
|
|
||||||
def run_diff(file1, file2, context=3):
|
def run_diff(file1, file2, context=3):
|
||||||
# returns: ok, is_different, patch
|
# returns: ok, is_different, patch
|
||||||
@ -22,13 +26,14 @@ def run_diff(file1, file2, context=3):
|
|||||||
|
|
||||||
class Chunk:
|
class Chunk:
|
||||||
|
|
||||||
__slots__ = ('is_context', 'left_start', 'right_start', 'left_count', 'right_count')
|
__slots__ = ('is_context', 'left_start', 'right_start', 'left_count', 'right_count', 'is_change')
|
||||||
|
|
||||||
def __init__(self, left_start, right_start, is_context=False):
|
def __init__(self, left_start, right_start, is_context=False):
|
||||||
self.is_context = is_context
|
self.is_context = is_context
|
||||||
self.left_start = left_start
|
self.left_start = left_start
|
||||||
self.right_start = right_start
|
self.right_start = right_start
|
||||||
self.left_count = self.right_count = 0
|
self.left_count = self.right_count = 0
|
||||||
|
self.is_change = False
|
||||||
|
|
||||||
def add_line(self):
|
def add_line(self):
|
||||||
self.right_count += 1
|
self.right_count += 1
|
||||||
@ -40,6 +45,10 @@ def context_line(self):
|
|||||||
self.left_count += 1
|
self.left_count += 1
|
||||||
self.right_count += 1
|
self.right_count += 1
|
||||||
|
|
||||||
|
def finalize(self):
|
||||||
|
if not self.is_context and self.left_count == self.right_count:
|
||||||
|
self.is_change = True
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return 'Chunk(is_context={}, left_start={}, left_count={}, right_start={}, right_count={})'.format(
|
return 'Chunk(is_context={}, left_start={}, left_count={}, right_start={}, right_count={})'.format(
|
||||||
self.is_context, self.left_start, self.left_count, self.right_start, self.right_count)
|
self.is_context, self.left_start, self.left_count, self.right_start, self.right_count)
|
||||||
@ -102,6 +111,8 @@ def finalize(self):
|
|||||||
raise ValueError('Left side line mismatch {} != {}'.format(c.left_start + c.left_count, self.left_start + self.left_count))
|
raise ValueError('Left side line mismatch {} != {}'.format(c.left_start + c.left_count, self.left_start + self.left_count))
|
||||||
if c.right_start + c.right_count != self.right_start + self.right_count:
|
if c.right_start + c.right_count != self.right_start + self.right_count:
|
||||||
raise ValueError('Left side line mismatch {} != {}'.format(c.right_start + c.right_count, self.right_start + self.right_count))
|
raise ValueError('Left side line mismatch {} != {}'.format(c.right_start + c.right_count, self.right_start + self.right_count))
|
||||||
|
for c in self.chunks:
|
||||||
|
c.finalize()
|
||||||
|
|
||||||
|
|
||||||
def parse_range(x):
|
def parse_range(x):
|
||||||
@ -166,6 +177,7 @@ def add_diff(self, file1, file2):
|
|||||||
self.jobs.append(file1)
|
self.jobs.append(file1)
|
||||||
|
|
||||||
def __call__(self, context=3):
|
def __call__(self, context=3):
|
||||||
|
global left_lines, right_lines
|
||||||
ans = {}
|
ans = {}
|
||||||
with concurrent.futures.ThreadPoolExecutor(max_workers=os.cpu_count()) as executor:
|
with concurrent.futures.ThreadPoolExecutor(max_workers=os.cpu_count()) as executor:
|
||||||
jobs = {executor.submit(run_diff, key, self.jmap[key], context): key for key in self.jobs}
|
jobs = {executor.submit(run_diff, key, self.jmap[key], context): key for key in self.jobs}
|
||||||
@ -179,6 +191,8 @@ def __call__(self, context=3):
|
|||||||
return 'Running git diff for {} vs. {} generated an exception: {}'.format(key[0], key[1], e)
|
return 'Running git diff for {} vs. {} generated an exception: {}'.format(key[0], key[1], e)
|
||||||
if not ok:
|
if not ok:
|
||||||
return output + '\nRunning git diff for {} vs. {} failed'.format(key[0], key[1])
|
return output + '\nRunning git diff for {} vs. {} failed'.format(key[0], key[1])
|
||||||
|
left_lines = lines_for_path(key[0])
|
||||||
|
right_lines = lines_for_path(key[1])
|
||||||
try:
|
try:
|
||||||
patch = parse_patch(output)
|
patch = parse_patch(output)
|
||||||
except Exception:
|
except Exception:
|
||||||
|
52
kittens/diff/speedup.c
Normal file
52
kittens/diff/speedup.c
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
/*
|
||||||
|
* speedup.c
|
||||||
|
* Copyright (C) 2018 Kovid Goyal <kovid at kovidgoyal.net>
|
||||||
|
*
|
||||||
|
* Distributed under terms of the GPL3 license.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "data-types.h"
|
||||||
|
|
||||||
|
static PyObject*
|
||||||
|
changed_center(PyObject *self UNUSED, PyObject *args) {
|
||||||
|
unsigned int prefix_count = 0, suffix_count = 0;
|
||||||
|
PyObject *lp, *rp;
|
||||||
|
if (!PyArg_ParseTuple(args, "UU", &lp, &rp)) return NULL;
|
||||||
|
const size_t left_len = PyUnicode_GET_LENGTH(lp), right_len = PyUnicode_GET_LENGTH(rp);
|
||||||
|
|
||||||
|
#define R(which, index) PyUnicode_READ(PyUnicode_KIND(which), PyUnicode_DATA(which), index)
|
||||||
|
while(prefix_count < MIN(left_len, right_len)) {
|
||||||
|
if (R(lp, prefix_count) != R(rp, prefix_count)) break;
|
||||||
|
prefix_count++;
|
||||||
|
}
|
||||||
|
if (left_len && right_len && prefix_count < MIN(left_len, right_len)) {
|
||||||
|
while(suffix_count < MIN(left_len - prefix_count, right_len - prefix_count)) {
|
||||||
|
if(R(lp, left_len - 1 - suffix_count) != R(rp, right_len - 1 - suffix_count)) break;
|
||||||
|
suffix_count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#undef R
|
||||||
|
return Py_BuildValue("II", prefix_count, suffix_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyMethodDef module_methods[] = {
|
||||||
|
{"changed_center", (PyCFunction)changed_center, METH_VARARGS, ""},
|
||||||
|
{NULL, NULL, 0, NULL} /* Sentinel */
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct PyModuleDef module = {
|
||||||
|
.m_base = PyModuleDef_HEAD_INIT,
|
||||||
|
.m_name = "diff_speedup", /* name of module */
|
||||||
|
.m_doc = NULL,
|
||||||
|
.m_size = -1,
|
||||||
|
.m_methods = module_methods
|
||||||
|
};
|
||||||
|
|
||||||
|
EXPORTED PyMODINIT_FUNC
|
||||||
|
PyInit_diff_speedup(void) {
|
||||||
|
PyObject *m;
|
||||||
|
|
||||||
|
m = PyModule_Create(&module);
|
||||||
|
if (m == NULL) return NULL;
|
||||||
|
return m;
|
||||||
|
}
|
23
kitty_tests/diff.py
Normal file
23
kitty_tests/diff.py
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# vim:fileencoding=utf-8
|
||||||
|
# License: GPL v3 Copyright: 2018, Kovid Goyal <kovid at kovidgoyal.net>
|
||||||
|
|
||||||
|
|
||||||
|
from . import BaseTest
|
||||||
|
|
||||||
|
|
||||||
|
class TestDiff(BaseTest):
|
||||||
|
|
||||||
|
def test_changed_center(self):
|
||||||
|
from kittens.diff.diff_speedup import changed_center
|
||||||
|
for left, right, prefix, suffix in [
|
||||||
|
('abc', 'def', '', ''),
|
||||||
|
('', 'def', '', ''),
|
||||||
|
('abc', '', '', ''),
|
||||||
|
('abc', 'abc', 'abc', ''),
|
||||||
|
('abc', 'abcdef', 'abc', ''),
|
||||||
|
('aa111bb', 'aa2bb', 'aa', 'bb'),
|
||||||
|
]:
|
||||||
|
pc, sc = changed_center(left, right)
|
||||||
|
for src in (left, right):
|
||||||
|
self.assertEqual((prefix, suffix), (src[:pc], src[-sc:] if sc else ''))
|
9
setup.py
9
setup.py
@ -453,9 +453,12 @@ def kittens_env():
|
|||||||
|
|
||||||
|
|
||||||
def compile_kittens(incremental, compilation_database, all_keys):
|
def compile_kittens(incremental, compilation_database, all_keys):
|
||||||
sources = ['kittens/unicode_input/unicode_names.c']
|
kenv = kittens_env()
|
||||||
all_headers = ['kittens/unicode_input/names.h', 'kitty/data-types.h']
|
for sources, all_headers, dest in [
|
||||||
compile_c_extension(kittens_env(), 'kittens/unicode_input/unicode_names', incremental, compilation_database, all_keys, sources, all_headers)
|
(['kittens/unicode_input/unicode_names.c'], ['kittens/unicode_input/names.h', 'kitty/data-types.h'], 'kittens/unicode_input/unicode_names'),
|
||||||
|
(['kittens/diff/speedup.c'], ['kitty/data-types.h'], 'kittens/diff/diff_speedup'),
|
||||||
|
]:
|
||||||
|
compile_c_extension(kenv, dest, incremental, compilation_database, all_keys, sources, all_headers)
|
||||||
|
|
||||||
|
|
||||||
def build(args, native_optimizations=True):
|
def build(args, native_optimizations=True):
|
||||||
|
Loading…
Reference in New Issue
Block a user