Files
textmate/Frameworks/buffer/src/spelling.cc
Allan Odgaard 9894969e67 Initial commit
2012-08-09 16:25:56 +02:00

86 lines
3.1 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include "meta_data.h"
#include <bundles/bundles.h>
#include <oak/oak.h>
#include <text/ctype.h>
#include <oak/duration.h>
#include <ns/spellcheck.h>
#include <oak/debug.h>
OAK_DEBUG_VAR(Buffer_Spelling);
namespace ng
{
bool spelling_t::misspelled_at (size_t i) const
{
tree_t::iterator it = _misspellings.upper_bound(i);
return it != _misspellings.begin() ? (--it)->second : false;
}
void spelling_t::did_parse (buffer_t const* buffer, size_t from, size_t to)
{
auto first = buffer->_scopes.lower_bound(from);
auto last = buffer->_scopes.upper_bound(to);
if(first != buffer->_scopes.begin() && from < first->first)
--from;
std::set<scope::scope_t> enabled, disabled;
foreach(pair, first, last)
{
if(enabled.find(pair->second) != enabled.end() || disabled.find(pair->second) != disabled.end())
continue;
bundles::item_ptr spellCheckingItem;
plist::any_t const& spellCheckingValue = bundles::value_for_setting("spellChecking", pair->second, &spellCheckingItem);
if(spellCheckingItem && !plist::is_true(spellCheckingValue))
disabled.insert(pair->second);
else enabled.insert(pair->second);
}
std::vector< std::pair<size_t, size_t> > ranges;
while(first != last)
{
scope::scope_t scope = first->second;
size_t i = std::max<ssize_t>(from, first->first);
size_t j = ++first == last ? to : first->first;
if(enabled.find(scope) != enabled.end())
{
if(ranges.empty() || ranges.back().second != i)
ranges.push_back(std::make_pair(i, j));
else ranges.back().second = j;
}
}
// TODO We should delay checking to the misspellings function. This way we wont spell check entire document on load etc.
_misspellings.remove(_misspellings.lower_bound(from), _misspellings.upper_bound(to));
iterate(r, ranges)
{
std::string const& text = buffer->substr(r->first, r->second);
D(DBF_Buffer_Spelling, bug("check: %s (%s)\n", text.c_str(), buffer->spelling_language().c_str()););
citerate(range, ns::spellcheck(text.data(), text.data() + text.size(), buffer->spelling_language(), buffer->spelling_tag()))
{
_misspellings.set(r->first + range->first, true);
_misspellings.set(r->first + range->last, false);
D(DBF_Buffer_Spelling, bug("bad: %s\n", text.substr(range->first, range->last - range->first).c_str()););
}
}
}
void spelling_t::replace (buffer_t* buffer, size_t from, size_t to, std::string const& str)
{
// TODO We need to keep a list of dirty ranges to minimize work done in did_parse — these ranges should be extended to “surrounding words”, e.g. if user inserts space into “sho‸rtcut” we need to re-check “sho” even though it is not included in the changed range.
_misspellings.replace(from, to, str.size());
}
std::map<size_t, bool> spelling_t::misspellings (buffer_t const* buffer, size_t from, size_t to) const
{
ASSERT_LE(from, to);
std::map<size_t, bool> res;
foreach(it, _misspellings.lower_bound(from), _misspellings.lower_bound(to))
res[it->first < from ? 0 : it->first - from] = it->second;
if(!res.empty() && res.begin()->second == false)
res[0] = true;
return res;
}
} /* ng */