mirror of
https://github.com/textmate/textmate.git
synced 2026-01-23 13:47:54 -05:00
Majority of the edits done using the following ruby script:
def update_loops(src)
dst, cnt = '', 0
block_indent, variable = nil, nil
src.each_line do |line|
if block_indent
if line =~ /^#{block_indent}([{}\t])|^\t*$/
block_indent = nil if $1 == '}'
line = line.gsub(%r{ ([^a-z>]) \(\*#{variable}\) | \*#{variable}\b | \b#{variable}(->) }x) do
$1.to_s + variable + ($2 == "->" ? "." : "")
end
else
block_indent = nil
end
elsif line =~ /^(\t*)c?iterate\((\w+), (?!diacritics::make_range)(.*\))$/
block_indent, variable = $1, $2
line = "#$1for(auto const& #$2 : #$3\n"
cnt += 1
end
dst << line
end
return dst, cnt
end
paths.each do |path|
src = IO.read(path)
cnt = 1
while cnt != 0
src, cnt = update_loops(src)
STDERR << "#{path}: #{cnt}\n"
end
File.open(path, "w") { |io| io << src }
end
386 lines
12 KiB
C++
386 lines
12 KiB
C++
#include "buffer.h"
|
|
#include "meta_data.h"
|
|
#include <oak/oak.h>
|
|
#include <text/utf8.h>
|
|
#include <text/parse.h>
|
|
#include <regexp/format_string.h>
|
|
#include <parse/grammar.h>
|
|
|
|
OAK_DEBUG_VAR(Buffer);
|
|
OAK_DEBUG_VAR(Buffer_Parsing);
|
|
|
|
namespace ng
|
|
{
|
|
buffer_t::buffer_t (char const* str) : _grammar_callback(*this), _revision(0), _next_revision(1), _spelling_language("en")
|
|
{
|
|
_meta_data.push_back((_symbols = std::make_shared<symbols_t>()).get());
|
|
_meta_data.push_back((_marks = std::make_shared<marks_t>()).get());
|
|
_meta_data.push_back((_pairs = std::make_shared<pairs_t>()).get());
|
|
_scopes.set(-1, "text");
|
|
|
|
if(str)
|
|
insert(0, str);
|
|
}
|
|
|
|
buffer_t::~buffer_t ()
|
|
{
|
|
if(_grammar)
|
|
_grammar->remove_callback(&_grammar_callback);
|
|
}
|
|
|
|
size_t buffer_t::size () const
|
|
{
|
|
return _storage.size();
|
|
}
|
|
|
|
char buffer_t::at (size_t i) const
|
|
{
|
|
return _storage.substr(i, i+1)[0];
|
|
}
|
|
|
|
uint32_t buffer_t::code_point (size_t& i, size_t& len) const
|
|
{
|
|
len = 1;
|
|
char ch = at(i);
|
|
if(!utf8::multibyte<char>::partial(ch))
|
|
return ch;
|
|
|
|
while(!utf8::multibyte<char>::is_start(ch))
|
|
{
|
|
ASSERT(0 < i);
|
|
ch = at(--i);
|
|
}
|
|
|
|
len = utf8::multibyte<char>::length(ch);
|
|
return utf8::to_ch(_storage.substr(i, i + len));
|
|
}
|
|
|
|
static bool is_non_base (uint32_t ch)
|
|
{
|
|
static CFCharacterSetRef const NonBaseSet = CFCharacterSetGetPredefined(kCFCharacterSetNonBase);
|
|
return 0xFF < ch && CFCharacterSetIsLongCharacterMember(NonBaseSet, ch);
|
|
}
|
|
|
|
size_t buffer_t::sanitize_index (size_t i) const
|
|
{
|
|
if(size() <= i)
|
|
return size();
|
|
while(utf8::multibyte<char>::partial(at(i)) && !utf8::multibyte<char>::is_start(at(i)))
|
|
--i;
|
|
uint32_t codePoint = utf8::to_ch(_storage.substr(i, i + (utf8::multibyte<char>::is_start(at(i)) ? utf8::multibyte<char>::length(at(i)) : 1)));
|
|
return is_non_base(codePoint) ? sanitize_index(i-1) : i;
|
|
}
|
|
|
|
std::string buffer_t::operator[] (size_t i) const
|
|
{
|
|
if(i == size())
|
|
return "";
|
|
|
|
size_t from = i;
|
|
size_t totalLen = 1;
|
|
uint32_t ch = code_point(from, totalLen);
|
|
|
|
while(from + totalLen < size())
|
|
{
|
|
size_t next = from + totalLen, nextLen;
|
|
if(is_non_base(code_point(next, nextLen)))
|
|
totalLen += nextLen;
|
|
else break;
|
|
}
|
|
|
|
while(is_non_base(ch))
|
|
{
|
|
ASSERT(from);
|
|
size_t len;
|
|
ch = code_point(--from, len);
|
|
totalLen += len;
|
|
}
|
|
|
|
return _storage.substr(from, from + totalLen);
|
|
}
|
|
|
|
std::string buffer_t::substr (size_t from, size_t to) const
|
|
{
|
|
return _storage.substr(from, to);
|
|
}
|
|
|
|
bool buffer_t::operator== (buffer_t const& rhs) const
|
|
{
|
|
return size() == rhs.size() && substr(0, size()) == rhs.substr(0, rhs.size());
|
|
}
|
|
|
|
size_t buffer_t::replace (size_t from, size_t to, std::string const& str)
|
|
{
|
|
size_t shrinkLeft = 0;
|
|
size_t shrinkRight = 0;
|
|
size_t len = str.size();
|
|
|
|
while(from + shrinkLeft < to && shrinkLeft < len && _storage[from + shrinkLeft] == str[shrinkLeft])
|
|
++shrinkLeft;
|
|
|
|
if(shrinkLeft < len)
|
|
{
|
|
while(shrinkLeft && utf8::multibyte<char>::partial(str[shrinkLeft]) && !utf8::multibyte<char>::is_start(str[shrinkLeft]))
|
|
--shrinkLeft;
|
|
}
|
|
|
|
while(from + shrinkLeft < to - shrinkRight && len - shrinkLeft - shrinkRight && _storage[to - shrinkRight - 1] == str[len - shrinkRight - 1])
|
|
++shrinkRight;
|
|
|
|
while(shrinkRight && utf8::multibyte<char>::partial(str[len - shrinkRight]) && !utf8::multibyte<char>::is_start(str[len - shrinkRight]))
|
|
--shrinkRight;
|
|
|
|
if(shrinkLeft == 0 && shrinkRight == 0)
|
|
return actual_replace(from, to, str);
|
|
|
|
actual_replace(from + shrinkLeft, to - shrinkRight, str.substr(shrinkLeft, len - shrinkLeft - shrinkRight));
|
|
return from + str.size();
|
|
}
|
|
|
|
size_t buffer_t::actual_replace (size_t from, size_t to, std::string const& str)
|
|
{
|
|
ASSERT_LE(from, to); ASSERT_LE(to, size());
|
|
_callbacks(&callback_t::will_replace, from, to, str);
|
|
|
|
_storage.erase(from, to);
|
|
_storage.insert(from, str.data(), str.size());
|
|
|
|
_dirty.replace(from, to, str.size(), false);
|
|
_dirty.set(from, true);
|
|
|
|
_hardlines.replace(from, to, str.size());
|
|
auto scopeIter = _scopes.upper_bound(to);
|
|
scope::scope_t preserveScope = scopeIter != _scopes.begin() && from < (--scopeIter)->first && scopeIter->first <= to ? scopeIter->second : scope::scope_t();
|
|
_scopes.replace(from, to, str.size());
|
|
if(preserveScope)
|
|
_scopes.set(from + str.size(), preserveScope);
|
|
_parser_states.replace(from, to, str.size(), false);
|
|
|
|
for(size_t i = 0; i < str.size(); ++i)
|
|
{
|
|
if(str[i] == '\n')
|
|
_hardlines.set(from + i, true);
|
|
}
|
|
|
|
for(auto const& hook : _meta_data)
|
|
hook->replace(this, from, to, str);
|
|
|
|
_callbacks(&callback_t::did_replace, from, to, str);
|
|
return from + str.size();
|
|
}
|
|
|
|
bool buffer_t::set_grammar (bundles::item_ptr const& grammarItem)
|
|
{
|
|
if(_grammar)
|
|
_grammar->remove_callback(&_grammar_callback);
|
|
_grammar.reset();
|
|
_scopes.clear();
|
|
_parser_states.clear();
|
|
_dirty.clear();
|
|
|
|
std::string rootScope = NULL_STR;
|
|
plist::get_key_path(grammarItem->plist(), bundles::kFieldGrammarScope, rootScope);
|
|
_scopes.set(-1, rootScope);
|
|
|
|
if(parse::grammar_ptr grammar = parse::parse_grammar(grammarItem))
|
|
{
|
|
_grammar = grammar;
|
|
_grammar->add_callback(&_grammar_callback);
|
|
_parser_states.set(-1, grammar->seed());
|
|
_dirty.set(0, true);
|
|
|
|
initiate_repair(10);
|
|
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void buffer_t::grammar_did_change ()
|
|
{
|
|
set_grammar(bundles::lookup(_grammar->uuid()));
|
|
}
|
|
|
|
scope::context_t buffer_t::scope (size_t i, bool includeDynamic) const
|
|
{
|
|
if(_scopes.empty())
|
|
return scope::context_t();
|
|
|
|
auto first = _scopes.lower_bound(i);
|
|
auto last = _scopes.find(i);
|
|
if(first != _scopes.begin())
|
|
--first;
|
|
if(last == _scopes.end())
|
|
last = first;
|
|
|
|
scope::scope_t left = first->second;
|
|
scope::scope_t right = last->second;
|
|
|
|
if(_spelling && includeDynamic)
|
|
{
|
|
if(i && _spelling->misspelled_at(i-1))
|
|
left.push_scope("dyn.misspelled");
|
|
if(i+i < size() && _spelling->misspelled_at(i))
|
|
right.push_scope("dyn.misspelled");
|
|
}
|
|
|
|
return scope::context_t(left, right);
|
|
}
|
|
|
|
std::map<size_t, scope::scope_t> buffer_t::scopes (size_t from, size_t to) const
|
|
{
|
|
ASSERT_LE(from, to); ASSERT_LE(to, size());
|
|
std::map<size_t, scope::scope_t> scopes;
|
|
auto first = _scopes.upper_bound(from);
|
|
auto last = _scopes.upper_bound(to);
|
|
if(first != _scopes.begin() && (first == _scopes.end() || (ssize_t)from < first->first))
|
|
{
|
|
auto it = first;
|
|
scopes.emplace(0, (--it)->second);
|
|
}
|
|
std::transform(first, last, std::inserter(scopes, scopes.end()), [&from](std::pair<ssize_t, scope::scope_t> const& pair){
|
|
return std::make_pair(pair.first - from, pair.second);
|
|
});
|
|
|
|
std::map<size_t, bool> const m = misspellings(from, to);
|
|
|
|
auto scopeIter = scopes.begin();
|
|
auto spellingIter = m.begin();
|
|
scope::scope_t scope = scopeIter->second;
|
|
bool misspelled = false;
|
|
|
|
while(spellingIter != m.end() || (misspelled && scopeIter != scopes.end()))
|
|
{
|
|
if(spellingIter == m.end())
|
|
{
|
|
scopeIter->second.push_scope("dyn.misspelled");
|
|
++scopeIter;
|
|
}
|
|
else if(scopeIter == scopes.end() || spellingIter->first < scopeIter->first)
|
|
{
|
|
if((misspelled = spellingIter->second) && scope.back() != "dyn.misspelled")
|
|
scope.push_scope("dyn.misspelled");
|
|
else if(scope.back() == "dyn.misspelled")
|
|
scope.pop_scope();
|
|
scopes.emplace(spellingIter->first, scope);
|
|
++spellingIter;
|
|
}
|
|
else
|
|
{
|
|
if(scopeIter->first == spellingIter->first)
|
|
{
|
|
misspelled = spellingIter->second;
|
|
++spellingIter;
|
|
}
|
|
|
|
if(misspelled)
|
|
scopeIter->second.push_scope("dyn.misspelled");
|
|
scope = scopeIter->second;
|
|
++scopeIter;
|
|
}
|
|
}
|
|
|
|
return scopes;
|
|
}
|
|
|
|
// =============
|
|
// = Meta data =
|
|
// =============
|
|
|
|
std::map<size_t, std::string> buffer_t::symbols () const { return _symbols->symbols(this); }
|
|
std::string buffer_t::symbol_at (size_t i) const { return _symbols->symbol_at(this, i); }
|
|
|
|
// ==================
|
|
// = Spell Checking =
|
|
// ==================
|
|
|
|
bool buffer_t::live_spelling () const { return _spelling ? true : false; }
|
|
std::string const& buffer_t::spelling_language () const { return _spelling_language; }
|
|
std::map<size_t, bool> buffer_t::misspellings (size_t from, size_t to) const { return _spelling ? _spelling->misspellings(this, from, to) : std::map<size_t, bool>(); }
|
|
std::pair<size_t, size_t> buffer_t::next_misspelling (size_t from) const { return _spelling ? _spelling->next_misspelling(from) : std::pair<size_t, size_t>(0, 0); }
|
|
ns::spelling_tag_t buffer_t::spelling_tag () const { return _spelling_tag; }
|
|
void buffer_t::recheck_spelling (size_t from, size_t to) { if(_spelling) _spelling->recheck(this, from, to); }
|
|
|
|
void buffer_t::set_live_spelling (bool flag)
|
|
{
|
|
remove_meta_data(_spelling.get());
|
|
_spelling.reset(flag ? new spelling_t : NULL);
|
|
add_meta_data(_spelling.get());
|
|
|
|
if(flag && _spelling)
|
|
_spelling->recheck(this, 0, size());
|
|
}
|
|
|
|
void buffer_t::set_spelling_language (std::string const& lang)
|
|
{
|
|
if(lang != _spelling_language)
|
|
{
|
|
_spelling_language = lang;
|
|
if(_spelling)
|
|
_spelling->recheck(this, 0, size());
|
|
}
|
|
}
|
|
|
|
// =========
|
|
// = Marks =
|
|
// =========
|
|
|
|
void buffer_t::set_mark (size_t index, std::string const& markType) { return _marks->set(index, markType); }
|
|
void buffer_t::remove_mark (size_t index, std::string const& markType) { return _marks->remove(index, markType); }
|
|
void buffer_t::remove_all_marks (std::string const& markType) { return _marks->remove_all(markType); }
|
|
std::string buffer_t::get_mark (size_t index, std::string const& markType) const { return _marks->get(index, markType); }
|
|
std::map<size_t, std::string> buffer_t::get_marks (size_t from, size_t to, std::string const& markType) const { return _marks->get_range(from, to, markType); }
|
|
std::pair<size_t, std::string> buffer_t::next_mark (size_t index, std::string const& markType) const { return _marks->next(index, markType); }
|
|
std::pair<size_t, std::string> buffer_t::prev_mark (size_t index, std::string const& markType) const { return _marks->prev(index, markType); }
|
|
|
|
// ========
|
|
// = to_s =
|
|
// ========
|
|
|
|
std::string to_s (buffer_t const& buf, size_t from, size_t to)
|
|
{
|
|
to = to != SIZE_T_MAX ? to : buf.size();
|
|
std::string res = "";
|
|
|
|
auto first = buf._scopes.upper_bound(from);
|
|
auto last = buf._scopes.lower_bound(to);
|
|
if(first != buf._scopes.begin())
|
|
--first;
|
|
|
|
scope::scope_t lastScope;
|
|
for(auto it = first; it != last; )
|
|
{
|
|
res.append(xml_difference(lastScope, it->second, "«", "»"));
|
|
size_t pos = std::max<ssize_t>(from, it->first);
|
|
lastScope = it->second;
|
|
++it;
|
|
res.append(buf.substr(pos, it == last ? to : it->first));
|
|
}
|
|
|
|
return res + xml_difference(lastScope, scope::scope_t(), "«", "»");
|
|
}
|
|
|
|
std::string to_xml (buffer_t const& buf, size_t from, size_t to)
|
|
{
|
|
to = to != SIZE_T_MAX ? to : buf.size();
|
|
std::string res = "";
|
|
|
|
auto first = buf._scopes.upper_bound(from);
|
|
auto last = buf._scopes.lower_bound(to);
|
|
if(first != buf._scopes.begin())
|
|
--first;
|
|
|
|
scope::scope_t lastScope;
|
|
for(auto it = first; it != last; )
|
|
{
|
|
res.append(xml_difference(lastScope, it->second, "<", ">"));
|
|
size_t pos = std::max<ssize_t>(from, it->first);
|
|
lastScope = it->second;
|
|
++it;
|
|
res.append(format_string::replace(buf.substr(pos, it == last ? to : it->first), "(<)|&", "&${1:?lt:amp};"));
|
|
}
|
|
return res + xml_difference(lastScope, scope::scope_t(), "<", ">");
|
|
}
|
|
|
|
} /* ng */
|