#include "meta_data.h" #include #include #include #include #include #include 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 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 > ranges; while(first != last) { scope::scope_t scope = first->second; size_t i = std::max(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 won’t 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 spelling_t::misspellings (buffer_t const* buffer, size_t from, size_t to) const { ASSERT_LE(from, to); std::map 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 */