Files
textmate/Frameworks/buffer/src/symbols.cc
Jacob Bandes-Storch d4ce498f60 Use 64-bit: numeric type fixes
Unfortunately a printf precision specifier (‘%.*s’) can not come with a width specifier so we have to cast to int. The width specifier ‘t’ is used for ptrdiff_t.
The int → NSInteger change fixed a bug with popup menu positioning, but there was no associated warning or error. It's possible there are more such bugs that we haven't found yet!
2012-08-28 21:32:47 +02:00

165 lines
4.5 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 <regexp/format_string.h>
#include <bundles/bundles.h>
#include <oak/oak.h>
#include <text/ctype.h>
#include <oak/duration.h>
namespace
{
struct transform_t
{
transform_t (std::string const& src) : src(src)
{
char const* it = src.data();
char const* last = it + src.size();
while(it != last)
{
if(text::is_space(*it) || *it == '\n')
{
++it;
}
else if(parse_char(it, last, '#'))
{
while(!parse_char(it, last, '\n') && it != last)
++it;
}
else if(parse_char(it, last, 's') && parse_char(it, last, '/'))
{
std::string regexp;
while(it != last && *it != '/')
{
if(*it == '\\' && it + 1 != last)
regexp += *it++;
regexp += *it++;
}
if(!parse_char(it, last, '/'))
{
fprintf(stderr, "malformed symbol transformation at offset %td (expected /): %s\n", it - src.data(), src.c_str());
return;
}
std::string format;
while(it != last && *it != '/')
{
if(*it == '\\' && it + 1 != last)
format += *it++;
format += *it++;
}
if(!parse_char(it, last, '/'))
{
fprintf(stderr, "malformed symbol transformation at offset %td (expected /): %s\n", it - src.data(), src.c_str());
return;
}
std::string options;
while(it != last && 'a' <= *it && *it <= 'z')
options += *it++;
parse_char(it, last, ';'); // semi-colon is optional, so we do not treat it as an error
records.push_back((record_t){ regexp::pattern_t(regexp, options), format, options.find('g') != std::string::npos });
}
else
{
fprintf(stderr, "malformed symbol transformation at offset %td (expected s, #, or space, found %c (0x%02x)): %s\n", it - src.data(), *it, *it, src.c_str());
return;
}
}
}
std::string expand (std::string const& str) const
{
static regexp::pattern_t newline("\n");
std::string res = replace(str, newline, format_string::format_string_t(" "));
iterate(it, records)
res = replace(res, it->regexp, it->format, it->repeat);
res = replace(res, newline, format_string::format_string_t(""));
return res;
}
private:
static bool parse_char (char const*& it, char const* last, char ch)
{
return it != last && *it == ch ? (++it, true) : false;
}
struct record_t
{
regexp::pattern_t regexp;
format_string::format_string_t format;
bool repeat;
};
std::string src;
std::vector<record_t> records;
};
}
namespace ng
{
void symbols_t::replace (buffer_t* buffer, size_t from, size_t to, std::string const& str) { _symbols.replace(from, to, str.size()); }
void symbols_t::did_parse (buffer_t const* buffer, size_t from, size_t to)
{
_symbols.remove(_symbols.lower_bound(from), _symbols.lower_bound(to));
std::set<scope::scope_t> all_scopes;
foreach(it, buffer->_scopes.lower_bound(from), buffer->_scopes.lower_bound(to))
all_scopes.insert(all_scopes.end(), it->second);
std::map<scope::scope_t, transform_t> transforms;
iterate(it, all_scopes)
{
if(plist::is_true(bundles::value_for_setting("showInSymbolList", *it)))
{
plist::any_t const& symbolTransformationValue = bundles::value_for_setting("symbolTransformation", *it);
std::string const* symbolTransformation = boost::get<std::string>(&symbolTransformationValue);
transforms.insert(std::make_pair(*it, transform_t(symbolTransformation ? *symbolTransformation : "")));
}
}
size_t beginOfSymbol = 0;
bool inSymbol = false;
transform_t* transform = NULL;
foreach(it, buffer->_scopes.lower_bound(from), buffer->_scopes.lower_bound(to))
{
std::map<scope::scope_t, transform_t>::iterator transformIt = transforms.find(it->second);
if(transformIt != transforms.end())
{
if(!inSymbol)
beginOfSymbol = it->first;
transform = &transformIt->second;
inSymbol = true;
}
else if(inSymbol)
{
_symbols.set(beginOfSymbol, transform->expand(buffer->substr(beginOfSymbol, it->first)));
inSymbol = false;
}
}
if(inSymbol)
_symbols.set(beginOfSymbol, transform->expand(buffer->substr(beginOfSymbol, to)));
}
std::map<size_t, std::string> symbols_t::symbols (buffer_t const* buffer) const
{
std::map<size_t, std::string> res;
iterate(it, _symbols)
res.insert(*it);
return res;
}
std::string symbols_t::symbol_at (buffer_t const* buffer, size_t i) const
{
tree_t::iterator it = _symbols.upper_bound(i);
if(it == _symbols.begin())
return NULL_STR;
return (--it)->second;
}
} /* ng */