<commit_before>#include "highlighters.hh"
#include "assert.hh"
#include "color_registry.hh"
#include "highlighter_group.hh"
#include "register_manager.hh"
#include "context.hh"
#include "string.hh"
#include "utf8.hh"
#include "utf8_iterator.hh"

#include "option_types.hh"

#include <sstream>
#include <locale>

namespace Kakoune
{

using namespace std::placeholders;

typedef boost::regex_iterator<BufferIterator> RegexIterator;

template<typename T>
void highlight_range(DisplayBuffer& display_buffer,
                     BufferIterator begin, BufferIterator end,
                     bool skip_replaced, T func)
{
    if (begin == end or end <= display_buffer.range().first
                     or begin >= display_buffer.range().second)
        return;

    for (auto& line : display_buffer.lines())
    {
        if (line.buffer_line() < begin.line() or  end.line() < line.buffer_line())
            continue;

        for (auto atom_it = line.begin(); atom_it != line.end(); ++atom_it)
        {
            bool is_replaced = atom_it->content.type() == AtomContent::ReplacedBufferRange;

            if (not atom_it->content.has_buffer_range() or
                (skip_replaced and is_replaced))
                continue;

            if (end <= atom_it->content.begin() or begin >= atom_it->content.end())
                continue;

            if (not is_replaced and begin > atom_it->content.begin())
                atom_it = ++line.split(atom_it, begin);

            if (not is_replaced and end < atom_it->content.end())
            {
                atom_it = line.split(atom_it, end);
                func(*atom_it);
                ++atom_it;
            }
            else
                func(*atom_it);
        }
    }
}

typedef std::unordered_map<size_t, const ColorPair*> ColorSpec;

class RegexColorizer
{
public:
    RegexColorizer(Regex regex, ColorSpec colors)
        : m_regex(std::move(regex)), m_colors(std::move(colors)),
          m_cache_timestamp(0)
    {
    }

    void operator()(DisplayBuffer& display_buffer)
    {
        update_cache_ifn(display_buffer.range());
        for (auto& match : m_cache_matches)
        {
            for (size_t n = 0; n < match.size(); ++n)
            {
                auto col_it = m_colors.find(n);
                if (col_it == m_colors.end())
                    continue;

                highlight_range(display_buffer, match[n].first, match[n].second, true,
                                [&](DisplayAtom& atom) { atom.colors = *col_it->second; });
            }
        }
    }

private:
    BufferRange m_cache_range;
    size_t      m_cache_timestamp;
    std::vector<boost::match_results<BufferIterator>> m_cache_matches;

    Regex     m_regex;
    ColorSpec m_colors;

    void update_cache_ifn(const BufferRange& range)
    {
        const Buffer& buf = range.first.buffer();
        if (m_cache_range.first.is_valid() and
            &m_cache_range.first.buffer() == &buf and
            buf.timestamp() == m_cache_timestamp and
            range.first >= m_cache_range.first and
            range.second <= m_cache_range.second)
           return;

        m_cache_matches.clear();
        m_cache_range.first  = buf.iterator_at_line_begin(range.first.line() - 10);
        m_cache_range.second = buf.iterator_at_line_end(range.second.line() + 10);
        m_cache_timestamp = buf.timestamp();

        RegexIterator re_it(m_cache_range.first, m_cache_range.second, m_regex);
        RegexIterator re_end;
        for (; re_it != re_end; ++re_it)
            m_cache_matches.push_back(*re_it);
    }
};

HighlighterAndId colorize_regex_factory(const HighlighterParameters params, const Window&)
{
    if (params.size() < 2)
        throw runtime_error("wrong parameter count");

    try
    {
        static Regex color_spec_ex(R"((\d+):(\w+(,\w+)?))");
        ColorSpec colors;
        for (auto it = params.begin() + 1;  it != params.end(); ++it)
        {
            boost::match_results<String::iterator> res;
            if (not boost::regex_match(it->begin(), it->end(), res, color_spec_ex))
                throw runtime_error("wrong colorspec: '" + *it +
                                     "' expected <capture>:<fgcolor>[,<bgcolor>]");

            int capture = str_to_int(String(res[1].first, res[1].second));
            const ColorPair*& color = colors[capture];
            color = &ColorRegistry::instance()[String(res[2].first, res[2].second)];
        }

        String id = "colre'" + params[0] + "'";

        Regex ex(params[0].begin(), params[0].end(),
                 boost::regex::perl | boost::regex::optimize);

        return HighlighterAndId(id, RegexColorizer(std::move(ex),
                                                   std::move(colors)));
    }
    catch (boost::regex_error& err)
    {
        throw runtime_error(String("regex error: ") + err.what());
    }
}

class SearchHighlighter
{
public:
    SearchHighlighter(const ColorSpec& colors)
        : m_colors(colors), m_colorizer(Regex(), m_colors) {}

    void operator()(DisplayBuffer& display_buffer)
    {
        memoryview<String> searches = RegisterManager::instance()['/'].values(Context{});
        if (searches.empty())
            return;
        const String& search = searches[0];
        if (search != m_last_search)
        {
            m_last_search = search;
            if (not m_last_search.empty())
                m_colorizer = RegexColorizer{Regex{m_last_search.begin(), m_last_search.end()}, m_colors};
        }
        if (not m_last_search.empty())
            m_colorizer(display_buffer);
    }

private:
    String         m_last_search;
    ColorSpec      m_colors;
    RegexColorizer m_colorizer;
};

HighlighterAndId highlight_search_factory(const HighlighterParameters params, const Window&)
{
    if (params.size() != 1)
        throw runtime_error("wrong parameter count");
    try
    {
        ColorSpec colors;
        colors[0] = &ColorRegistry::instance()[params[0]];
        return {"hlsearch", SearchHighlighter{colors}};
    }
    catch (boost::regex_error& err)
    {
        throw runtime_error(String("regex error: ") + err.what());
    }
};

void expand_tabulations(const OptionManager& options, DisplayBuffer& display_buffer)
{
    const int tabstop = options["tabstop"].get<int>();
    for (auto& line : display_buffer.lines())
    {
        for (auto atom_it = line.begin(); atom_it != line.end(); ++atom_it)
        {
            if (atom_it->content.type() != AtomContent::BufferRange)
                continue;

            auto begin = atom_it->content.begin();
            auto end = atom_it->content.end();
            for (BufferIterator it = begin; it != end; ++it)
            {
                if (*it == '\t')
                {
                    if (it != begin)
                        atom_it = ++line.split(atom_it, it);
                    if (it+1 != end)
                        atom_it = line.split(atom_it, it+1);

                    int column = 0;
                    for (auto line_it = it.buffer().iterator_at_line_begin(it);
                         line_it != it; ++line_it)
                    {
                        assert(*line_it != '\n');
                        if (*line_it == '\t')
                            column += tabstop - (column % tabstop);
                        else
                           ++column;
                    }

                    int count = tabstop - (column % tabstop);
                    String padding;
                    for (int i = 0; i < count; ++i)
                        padding += ' ';
                    atom_it->content.replace(padding);
                    break;
                }
            }
        }
    }
}

void show_line_numbers(DisplayBuffer& display_buffer)
{
    LineCount last_line = display_buffer.range().first.buffer().line_count();
    int digit_count = 0;
    for (LineCount c = last_line; c > 0; c /= 10)
        ++digit_count;

    char format[] = "%?d ";
    format[1] = '0' + digit_count;
    auto& colors = ColorRegistry::instance()["LineNumbers"];
    for (auto& line : display_buffer.lines())
    {
        char buffer[10];
        snprintf(buffer, 10, format, (int)line.buffer_line() + 1);
        DisplayAtom atom = DisplayAtom(AtomContent(buffer));
        atom.colors = colors;
        line.insert(line.begin(), std::move(atom));
    }
}

void highlight_selections(const Window& window, DisplayBuffer& display_buffer)
{
    const bool only_cursor = window.is_editing() and window.options()["insert_hide_sel"].get<bool>();
    for (size_t i = 0; i < window.selections().size(); ++i)
    {
        auto& sel = window.selections()[i];
        const bool forward = sel.first() <= sel.last();
        BufferIterator begin = forward ? sel.first() : utf8::next(sel.last());
        BufferIterator end   = forward ? sel.last() : utf8::next(sel.first());

        const bool primary = (i == window.main_selection_index());
        if (not only_cursor)
        {
            ColorPair sel_colors = ColorRegistry::instance()[primary ? "PrimarySelection" : "SecondarySelection"];
            highlight_range(display_buffer, begin, end, false,
                            [&](DisplayAtom& atom) { atom.colors = sel_colors; });
        }
        ColorPair cur_colors = ColorRegistry::instance()[primary ? "PrimaryCursor" : "SecondaryCursor"];
        highlight_range(display_buffer, sel.last(), utf8::next(sel.last()), false,
                        [&](DisplayAtom& atom) { atom.colors = cur_colors; });
    }
}

void expand_unprintable(DisplayBuffer& display_buffer)
{
    for (auto& line : display_buffer.lines())
    {
        for (auto atom_it = line.begin(); atom_it != line.end(); ++atom_it)
        {
            if (atom_it->content.type() == AtomContent::BufferRange)
            {
                using Utf8It = utf8::utf8_iterator<BufferIterator, utf8::InvalidBytePolicy::Pass>;
                for (Utf8It it = atom_it->content.begin(), end = atom_it->content.end(); it != end; ++it)
                {
                    Codepoint cp = *it;
                    if (cp != '\n' and not std::isprint((wchar_t)cp, std::locale()))
                    {
                        std::ostringstream oss;
                        oss << "U+" << std::hex << cp;
                        String str = oss.str();
                        if (it.underlying_iterator() != atom_it->content.begin())
                            atom_it = ++line.split(atom_it, it.underlying_iterator());
                        if ((it+1).underlying_iterator() != atom_it->content.end())
                            atom_it = line.split(atom_it, (it+1).underlying_iterator());
                        atom_it->content.replace(str);
                        atom_it->colors = { Color::Red, Color::Black };
                        break;
                    }
                }
            }
        }
    }
}

class FlagLines
{
public:
    FlagLines(Color bg, String option_name, const OptionManager& options)
        : m_bg(bg), m_option_name(std::move(option_name)),
          m_options(options)
    {
        // trigger an exception if option is not of right type.
        m_options[m_option_name].get<std::vector<LineAndFlag>>();
    }

    void operator()(DisplayBuffer& display_buffer)
    {
        auto& lines = m_options[m_option_name].get<std::vector<LineAndFlag>>();

        CharCount width = 0;
        for (auto& l : lines)
             width = std::max(width, l.flag.char_length());
        const String empty{' ', width};
        for (auto& line : display_buffer.lines())
        {
            int line_num = (int)line.buffer_line() + 1;
            auto it = find_if(lines, [&](const LineAndFlag& l) { return l.line == line_num; });
            DisplayAtom atom{AtomContent(it != lines.end() ? it->flag : empty)};
            atom.colors = { it != lines.end() ? it->color : Color::Default , m_bg };
            line.insert(line.begin(), std::move(atom));
        }
    }

private:
    Color m_bg;
    String m_option_name;
    const OptionManager& m_options;
};

HighlighterAndId flag_lines_factory(const HighlighterParameters& params, const Window& window)
{
    if (params.size() != 2)
        throw runtime_error("wrong parameter count");

    return {"hlflags_" + params[1], FlagLines{str_to_color(params[0]), params[1], window.options()}};
}

template<void (*highlighter_func)(DisplayBuffer&)>
class SimpleHighlighterFactory
{
public:
    SimpleHighlighterFactory(const String& id) : m_id(id) {}

    HighlighterAndId operator()(const HighlighterParameters& params, const Window&) const
    {
        return HighlighterAndId(m_id, HighlighterFunc(highlighter_func));
    }
private:
    String m_id;
};

HighlighterAndId highlighter_group_factory(const HighlighterParameters& params, const Window&)
{
    if (params.size() != 1)
        throw runtime_error("wrong parameter count");

    return HighlighterAndId(params[0], HighlighterGroup());
}

void register_highlighters()
{
    HighlighterRegistry& registry = HighlighterRegistry::instance();

    registry.register_func("number_lines", SimpleHighlighterFactory<show_line_numbers>("number_lines"));
    registry.register_func("regex", colorize_regex_factory);
    registry.register_func("search", highlight_search_factory);
    registry.register_func("group", highlighter_group_factory);
    registry.register_func("flag_lines", flag_lines_factory);
}

}
<commit_msg>add regex_option highlighter, which takes a regex option name and highlight all its matches<commit_after>#include "highlighters.hh"
#include "assert.hh"
#include "color_registry.hh"
#include "highlighter_group.hh"
#include "register_manager.hh"
#include "context.hh"
#include "string.hh"
#include "utf8.hh"
#include "utf8_iterator.hh"

#include "option_types.hh"

#include <sstream>
#include <locale>

namespace Kakoune
{

using namespace std::placeholders;

typedef boost::regex_iterator<BufferIterator> RegexIterator;

template<typename T>
void highlight_range(DisplayBuffer& display_buffer,
                     BufferIterator begin, BufferIterator end,
                     bool skip_replaced, T func)
{
    if (begin == end or end <= display_buffer.range().first
                     or begin >= display_buffer.range().second)
        return;

    for (auto& line : display_buffer.lines())
    {
        if (line.buffer_line() < begin.line() or  end.line() < line.buffer_line())
            continue;

        for (auto atom_it = line.begin(); atom_it != line.end(); ++atom_it)
        {
            bool is_replaced = atom_it->content.type() == AtomContent::ReplacedBufferRange;

            if (not atom_it->content.has_buffer_range() or
                (skip_replaced and is_replaced))
                continue;

            if (end <= atom_it->content.begin() or begin >= atom_it->content.end())
                continue;

            if (not is_replaced and begin > atom_it->content.begin())
                atom_it = ++line.split(atom_it, begin);

            if (not is_replaced and end < atom_it->content.end())
            {
                atom_it = line.split(atom_it, end);
                func(*atom_it);
                ++atom_it;
            }
            else
                func(*atom_it);
        }
    }
}

typedef std::unordered_map<size_t, const ColorPair*> ColorSpec;

class RegexColorizer
{
public:
    RegexColorizer(Regex regex, ColorSpec colors)
        : m_regex(std::move(regex)), m_colors(std::move(colors)),
          m_cache_timestamp(0)
    {
    }

    void operator()(DisplayBuffer& display_buffer)
    {
        update_cache_ifn(display_buffer.range());
        for (auto& match : m_cache_matches)
        {
            for (size_t n = 0; n < match.size(); ++n)
            {
                auto col_it = m_colors.find(n);
                if (col_it == m_colors.end())
                    continue;

                highlight_range(display_buffer, match[n].first, match[n].second, true,
                                [&](DisplayAtom& atom) { atom.colors = *col_it->second; });
            }
        }
    }

private:
    BufferRange m_cache_range;
    size_t      m_cache_timestamp;
    std::vector<boost::match_results<BufferIterator>> m_cache_matches;

    Regex     m_regex;
    ColorSpec m_colors;

    void update_cache_ifn(const BufferRange& range)
    {
        const Buffer& buf = range.first.buffer();
        if (m_cache_range.first.is_valid() and
            &m_cache_range.first.buffer() == &buf and
            buf.timestamp() == m_cache_timestamp and
            range.first >= m_cache_range.first and
            range.second <= m_cache_range.second)
           return;

        m_cache_matches.clear();
        m_cache_range.first  = buf.iterator_at_line_begin(range.first.line() - 10);
        m_cache_range.second = buf.iterator_at_line_end(range.second.line() + 10);
        m_cache_timestamp = buf.timestamp();

        RegexIterator re_it(m_cache_range.first, m_cache_range.second, m_regex);
        RegexIterator re_end;
        for (; re_it != re_end; ++re_it)
            m_cache_matches.push_back(*re_it);
    }
};

HighlighterAndId colorize_regex_factory(const HighlighterParameters params, const Window&)
{
    if (params.size() < 2)
        throw runtime_error("wrong parameter count");

    try
    {
        static Regex color_spec_ex(R"((\d+):(\w+(,\w+)?))");
        ColorSpec colors;
        for (auto it = params.begin() + 1;  it != params.end(); ++it)
        {
            boost::match_results<String::iterator> res;
            if (not boost::regex_match(it->begin(), it->end(), res, color_spec_ex))
                throw runtime_error("wrong colorspec: '" + *it +
                                     "' expected <capture>:<fgcolor>[,<bgcolor>]");

            int capture = str_to_int(String(res[1].first, res[1].second));
            const ColorPair*& color = colors[capture];
            color = &ColorRegistry::instance()[String(res[2].first, res[2].second)];
        }

        String id = "colre'" + params[0] + "'";

        Regex ex(params[0].begin(), params[0].end(),
                 boost::regex::perl | boost::regex::optimize);

        return HighlighterAndId(id, RegexColorizer(std::move(ex),
                                                   std::move(colors)));
    }
    catch (boost::regex_error& err)
    {
        throw runtime_error(String("regex error: ") + err.what());
    }
}

template<typename RegexGetter>
class DynamicRegexHighlighter
{
public:
    DynamicRegexHighlighter(const ColorSpec& colors, RegexGetter getter)
        : m_regex_getter(getter), m_colors(colors), m_colorizer(Regex(), m_colors) {}

    void operator()(DisplayBuffer& display_buffer)
    {
        Regex regex = m_regex_getter();
        if (regex != m_last_regex)
        {
            m_last_regex = regex;
            if (not m_last_regex.empty())
                m_colorizer = RegexColorizer{m_last_regex, m_colors};
        }
        if (not m_last_regex.empty())
            m_colorizer(display_buffer);
    }

private:
    Regex          m_last_regex;
    ColorSpec      m_colors;
    RegexColorizer m_colorizer;
    RegexGetter    m_regex_getter;
};

HighlighterAndId highlight_search_factory(const HighlighterParameters params, const Window&)
{
    if (params.size() != 1)
        throw runtime_error("wrong parameter count");
    try
    {
        ColorSpec colors { { 0, &ColorRegistry::instance()[params[0]] } };
        auto get_regex = []{
            auto s = RegisterManager::instance()['/'].values(Context{});
            return s.empty() ? Regex{} : Regex{s[0].begin(), s[0].end()};
        };
        return {"hlsearch", DynamicRegexHighlighter<decltype(get_regex)>{colors, get_regex}};
    }
    catch (boost::regex_error& err)
    {
        throw runtime_error(String("regex error: ") + err.what());
    }
};

HighlighterAndId highlight_regex_option_factory(const HighlighterParameters params, const Window& window)
{
    if (params.size() != 2)
        throw runtime_error("wrong parameter count");

    ColorSpec colors { { 0, &ColorRegistry::instance()[params[1]] } };
    String option_name = params[0];
    const OptionManager& options = window.options();
    // verify option type now
    options[option_name].get<Regex>();

    auto get_regex = [option_name, &options]{ return options[option_name].get<Regex>(); };
    return {"hloption_" + option_name, DynamicRegexHighlighter<decltype(get_regex)>{colors, get_regex}};
};

void expand_tabulations(const OptionManager& options, DisplayBuffer& display_buffer)
{
    const int tabstop = options["tabstop"].get<int>();
    for (auto& line : display_buffer.lines())
    {
        for (auto atom_it = line.begin(); atom_it != line.end(); ++atom_it)
        {
            if (atom_it->content.type() != AtomContent::BufferRange)
                continue;

            auto begin = atom_it->content.begin();
            auto end = atom_it->content.end();
            for (BufferIterator it = begin; it != end; ++it)
            {
                if (*it == '\t')
                {
                    if (it != begin)
                        atom_it = ++line.split(atom_it, it);
                    if (it+1 != end)
                        atom_it = line.split(atom_it, it+1);

                    int column = 0;
                    for (auto line_it = it.buffer().iterator_at_line_begin(it);
                         line_it != it; ++line_it)
                    {
                        assert(*line_it != '\n');
                        if (*line_it == '\t')
                            column += tabstop - (column % tabstop);
                        else
                           ++column;
                    }

                    int count = tabstop - (column % tabstop);
                    String padding;
                    for (int i = 0; i < count; ++i)
                        padding += ' ';
                    atom_it->content.replace(padding);
                    break;
                }
            }
        }
    }
}

void show_line_numbers(DisplayBuffer& display_buffer)
{
    LineCount last_line = display_buffer.range().first.buffer().line_count();
    int digit_count = 0;
    for (LineCount c = last_line; c > 0; c /= 10)
        ++digit_count;

    char format[] = "%?d ";
    format[1] = '0' + digit_count;
    auto& colors = ColorRegistry::instance()["LineNumbers"];
    for (auto& line : display_buffer.lines())
    {
        char buffer[10];
        snprintf(buffer, 10, format, (int)line.buffer_line() + 1);
        DisplayAtom atom = DisplayAtom(AtomContent(buffer));
        atom.colors = colors;
        line.insert(line.begin(), std::move(atom));
    }
}

void highlight_selections(const Window& window, DisplayBuffer& display_buffer)
{
    const bool only_cursor = window.is_editing() and window.options()["insert_hide_sel"].get<bool>();
    for (size_t i = 0; i < window.selections().size(); ++i)
    {
        auto& sel = window.selections()[i];
        const bool forward = sel.first() <= sel.last();
        BufferIterator begin = forward ? sel.first() : utf8::next(sel.last());
        BufferIterator end   = forward ? sel.last() : utf8::next(sel.first());

        const bool primary = (i == window.main_selection_index());
        if (not only_cursor)
        {
            ColorPair sel_colors = ColorRegistry::instance()[primary ? "PrimarySelection" : "SecondarySelection"];
            highlight_range(display_buffer, begin, end, false,
                            [&](DisplayAtom& atom) { atom.colors = sel_colors; });
        }
        ColorPair cur_colors = ColorRegistry::instance()[primary ? "PrimaryCursor" : "SecondaryCursor"];
        highlight_range(display_buffer, sel.last(), utf8::next(sel.last()), false,
                        [&](DisplayAtom& atom) { atom.colors = cur_colors; });
    }
}

void expand_unprintable(DisplayBuffer& display_buffer)
{
    for (auto& line : display_buffer.lines())
    {
        for (auto atom_it = line.begin(); atom_it != line.end(); ++atom_it)
        {
            if (atom_it->content.type() == AtomContent::BufferRange)
            {
                using Utf8It = utf8::utf8_iterator<BufferIterator, utf8::InvalidBytePolicy::Pass>;
                for (Utf8It it = atom_it->content.begin(), end = atom_it->content.end(); it != end; ++it)
                {
                    Codepoint cp = *it;
                    if (cp != '\n' and not std::isprint((wchar_t)cp, std::locale()))
                    {
                        std::ostringstream oss;
                        oss << "U+" << std::hex << cp;
                        String str = oss.str();
                        if (it.underlying_iterator() != atom_it->content.begin())
                            atom_it = ++line.split(atom_it, it.underlying_iterator());
                        if ((it+1).underlying_iterator() != atom_it->content.end())
                            atom_it = line.split(atom_it, (it+1).underlying_iterator());
                        atom_it->content.replace(str);
                        atom_it->colors = { Color::Red, Color::Black };
                        break;
                    }
                }
            }
        }
    }
}

class FlagLines
{
public:
    FlagLines(Color bg, String option_name, const OptionManager& options)
        : m_bg(bg), m_option_name(std::move(option_name)),
          m_options(options)
    {
        // trigger an exception if option is not of right type.
        m_options[m_option_name].get<std::vector<LineAndFlag>>();
    }

    void operator()(DisplayBuffer& display_buffer)
    {
        auto& lines = m_options[m_option_name].get<std::vector<LineAndFlag>>();

        CharCount width = 0;
        for (auto& l : lines)
             width = std::max(width, l.flag.char_length());
        const String empty{' ', width};
        for (auto& line : display_buffer.lines())
        {
            int line_num = (int)line.buffer_line() + 1;
            auto it = find_if(lines, [&](const LineAndFlag& l) { return l.line == line_num; });
            DisplayAtom atom{AtomContent(it != lines.end() ? it->flag : empty)};
            atom.colors = { it != lines.end() ? it->color : Color::Default , m_bg };
            line.insert(line.begin(), std::move(atom));
        }
    }

private:
    Color m_bg;
    String m_option_name;
    const OptionManager& m_options;
};

HighlighterAndId flag_lines_factory(const HighlighterParameters& params, const Window& window)
{
    if (params.size() != 2)
        throw runtime_error("wrong parameter count");

    return {"hlflags_" + params[1], FlagLines{str_to_color(params[0]), params[1], window.options()}};
}

template<void (*highlighter_func)(DisplayBuffer&)>
class SimpleHighlighterFactory
{
public:
    SimpleHighlighterFactory(const String& id) : m_id(id) {}

    HighlighterAndId operator()(const HighlighterParameters& params, const Window&) const
    {
        return HighlighterAndId(m_id, HighlighterFunc(highlighter_func));
    }
private:
    String m_id;
};

HighlighterAndId highlighter_group_factory(const HighlighterParameters& params, const Window&)
{
    if (params.size() != 1)
        throw runtime_error("wrong parameter count");

    return HighlighterAndId(params[0], HighlighterGroup());
}

void register_highlighters()
{
    HighlighterRegistry& registry = HighlighterRegistry::instance();

    registry.register_func("number_lines", SimpleHighlighterFactory<show_line_numbers>("number_lines"));
    registry.register_func("regex", colorize_regex_factory);
    registry.register_func("regex_option", highlight_regex_option_factory);
    registry.register_func("search", highlight_search_factory);
    registry.register_func("group", highlighter_group_factory);
    registry.register_func("flag_lines", flag_lines_factory);
}

}
<|endoftext|>


<commit_before>/*
 * Written by Nitin Kumar Maharana
 * nitin.maharana@gmail.com
 */

/**
 * Definition for binary tree with next pointer.
 * struct TreeLinkNode {
 *  int val;
 *  TreeLinkNode *left, *right, *next;
 *  TreeLinkNode(int x) : val(x), left(NULL), right(NULL), next(NULL) {}
 * };
 */

//Iterative Solution.
class Solution {
    queue<TreeLinkNode*> memory;
public:
    void connect(TreeLinkNode *root) {
        if(!root)
            return;

        memory.push(root);

        TreeLinkNode *front;

        while(!memory.empty())
        {
            front = memory.front();
            memory.pop();

            if(front->left)
            {
                front->left->next = front->right;
                memory.push(front->left);
            }

            if(front->next && front->right)
                front->right->next = front->next->left;

            if(front->right)
                memory.push(front->right);
        }
    }
};

//Recursive Solution.
class Solution {
public:
    void connect(TreeLinkNode *root) {
        if(!root)
            return;

        if(root->left)
            root->left->next = root->right;

        if(root->next && root->right)
            root->right->next = root->next->left;

        connect(root->left);
        connect(root->right);
    }
};

//One More Recursive Solution - Works for any tree. O(N) - Time, O(H) - Space (Except Recursion Stack).
class Solution {
    void connect(TreeLinkNode* root, unordered_map<int, TreeLinkNode*>& memory, int level)
    {
        if(root == nullptr)
            return;

        if(memory.find(level) != memory.end())
            memory[level]->next = root;

        memory[level] = root;

        connect(root->left, memory, level+1);
        connect(root->right, memory, level+1);

        return;
    }
public:
    void connect(TreeLinkNode *root) {
        if(root == nullptr)
            return;

        unordered_map<int, TreeLinkNode*> memory;
        connect(root, memory, 0);

        return;
    }
};

//One More Recursive Solution - Works for any tree. O(N) - Time, O(1) - Space (Except Recursion Stack).
class Solution {
    void connectUtil(TreeLinkNode *root)
    {
        if(root == nullptr)
            return;

        if(root->left)
        {
            if(root->right)
                root->left->next = root->right;
            else if(root->next)
            {
                if(root->next->left)
                    root->left->next = root->next->left;
                else
                    root->left->next = root->next->right;
            }
            else
                root->left->next = NULL;
        }

        if(root->right)
        {
            if(root->next)
            {
                if(root->next->left)
                    root->right->next = root->next->left;
                else
                    root->right->next = root->next->right;
            }
            else
                root->right->next = NULL;
        }

        connectUtil(root->left);
        connectUtil(root->right);

        return;
    }
public:
    void connect(TreeLinkNode *root) {
        if(root == nullptr)
            return;

        root->next = NULL;

        connectUtil(root);

        return;
    }
};<commit_msg>116. Populating Next Right Pointers in Each Node - Added some more solutions(Works for any tree).<commit_after>/*
 * Written by Nitin Kumar Maharana
 * nitin.maharana@gmail.com
 */

/**
 * Definition for binary tree with next pointer.
 * struct TreeLinkNode {
 *  int val;
 *  TreeLinkNode *left, *right, *next;
 *  TreeLinkNode(int x) : val(x), left(NULL), right(NULL), next(NULL) {}
 * };
 */

//Iterative Solution.
class Solution {
    queue<TreeLinkNode*> memory;
public:
    void connect(TreeLinkNode *root) {
        if(!root)
            return;

        memory.push(root);

        TreeLinkNode *front;

        while(!memory.empty())
        {
            front = memory.front();
            memory.pop();

            if(front->left)
            {
                front->left->next = front->right;
                memory.push(front->left);
            }

            if(front->next && front->right)
                front->right->next = front->next->left;

            if(front->right)
                memory.push(front->right);
        }
    }
};

//Recursive Solution.
class Solution {
public:
    void connect(TreeLinkNode *root) {
        if(!root)
            return;

        if(root->left)
            root->left->next = root->right;

        if(root->next && root->right)
            root->right->next = root->next->left;

        connect(root->left);
        connect(root->right);
    }
};

//One More Recursive Solution - Works for any tree. O(N) - Time, O(H) - Space (Except Recursion Stack).
class Solution {
    void connect(TreeLinkNode* root, unordered_map<int, TreeLinkNode*>& memory, int level)
    {
        if(root == nullptr)
            return;

        if(memory.find(level) != memory.end())
            memory[level]->next = root;

        memory[level] = root;

        connect(root->left, memory, level+1);
        connect(root->right, memory, level+1);

        return;
    }
public:
    void connect(TreeLinkNode *root) {
        if(root == nullptr)
            return;

        unordered_map<int, TreeLinkNode*> memory;
        connect(root, memory, 0);

        return;
    }
};

//One More Iterative Solution - Works for any tree. Time - O(N), Space - O(1).
class Solution {
    TreeLinkNode* getNext(TreeLinkNode *root)
    {
        root = root->next;

        while(root)
        {
            if(root->left)
                return root->left;

            if(root->right)
                return root->right;

            root = root->next;
        }

        return NULL;
    }
public:
    void connect(TreeLinkNode *root) {
        if(root == NULL)
            return;

        root->next = NULL;

        TreeLinkNode *ptr1, *ptr2;

        ptr1 = root;

        while(ptr1)
        {
            ptr2 = ptr1;

            while(ptr2)
            {
                if(ptr2->left)
                {
                    if(ptr2->right)
                        ptr2->left->next = ptr2->right;
                    else
                        ptr2->left->next = getNext(ptr2);
                }

                if(ptr2->right)
                    ptr2->right->next = getNext(ptr2);

                ptr2 = ptr2->next;
            }

            if(ptr1->left)
                ptr1 = ptr1->left;
            else if(ptr1->right)
                ptr1 = ptr1->right;
            else
                ptr1 = getNext(ptr1);
        }

        return;
    }
};

/*
 * One More Recursive Solution - Works for any tree. Time - O(N), Space - O(1) [Except Recursion Stack].
 * For some input, It would be TLE, as the problem assumes complete binary tree, it expects to be run on less time.
 * As this does more work even for complete tree or any tree. So TLE.
 */
class Solution {
    TreeLinkNode* getNext(TreeLinkNode *root)
    {
        root = root->next;

        while(root)
        {
            if(root->left)
                return root->left;

            if(root->right)
                return root->right;

            root = root->next;
        }

        return NULL;
    }

    void connectUtil(TreeLinkNode *root)
    {
        if(root == NULL)
            return;

        if(root->left)
        {
            if(root->right)
                root->left->next = root->right;
            else
                root->left->next = getNext(root);
        }

        if(root->right)
            root->right->next = getNext(root);

        connectUtil(root->next);
        connectUtil(root->left);
        connectUtil(root->right);

        return;
    }
public:
    void connect(TreeLinkNode *root) {
        if(root == NULL)
            return;

        root->next = NULL;

        connectUtil(root);

        return;
    }
};<|endoftext|>


<commit_before>#include "highlighters.hh"
#include "assert.hh"
#include "color_registry.hh"
#include "highlighter_group.hh"
#include "register_manager.hh"
#include "context.hh"
#include "string.hh"
#include "utf8.hh"
#include "utf8_iterator.hh"

#include <sstream>
#include <locale>

namespace Kakoune
{

using namespace std::placeholders;

typedef boost::regex_iterator<BufferIterator> RegexIterator;

template<typename T>
void highlight_range(DisplayBuffer& display_buffer,
                     BufferIterator begin, BufferIterator end,
                     bool skip_replaced, T func)
{
    if (begin == end or end <= display_buffer.range().first
                     or begin >= display_buffer.range().second)
        return;

    for (auto& line : display_buffer.lines())
    {
        if (line.buffer_line() < begin.line() or  end.line() < line.buffer_line())
            continue;

        for (auto atom_it = line.begin(); atom_it != line.end(); ++atom_it)
        {
            bool is_replaced = atom_it->content.type() == AtomContent::ReplacedBufferRange;

            if (not atom_it->content.has_buffer_range() or
                (skip_replaced and is_replaced))
                continue;

            if (end <= atom_it->content.begin() or begin >= atom_it->content.end())
                continue;

            if (not is_replaced and begin > atom_it->content.begin())
                atom_it = ++line.split(atom_it, begin);

            if (not is_replaced and end < atom_it->content.end())
            {
                atom_it = line.split(atom_it, end);
                func(*atom_it);
                ++atom_it;
            }
            else
                func(*atom_it);
        }
    }
}

typedef std::unordered_map<size_t, const ColorPair*> ColorSpec;

class RegexColorizer
{
public:
    RegexColorizer(Regex regex, ColorSpec colors)
        : m_regex(std::move(regex)), m_colors(std::move(colors)),
          m_cache_timestamp(0)
    {
    }

    void operator()(DisplayBuffer& display_buffer)
    {
        update_cache_ifn(display_buffer.range());
        for (auto& match : m_cache_matches)
        {
            for (size_t n = 0; n < match.size(); ++n)
            {
                auto col_it = m_colors.find(n);
                if (col_it == m_colors.end())
                    continue;

                highlight_range(display_buffer, match[n].first, match[n].second, true,
                                [&](DisplayAtom& atom) {
                                    atom.fg_color = col_it->second->first;
                                    atom.bg_color = col_it->second->second;
                                });
            }
        }
    }

private:
    BufferRange m_cache_range;
    size_t      m_cache_timestamp;
    std::vector<boost::match_results<BufferIterator>> m_cache_matches;

    Regex     m_regex;
    ColorSpec m_colors;

    void update_cache_ifn(const BufferRange& range)
    {
        const Buffer& buf = range.first.buffer();
        if (m_cache_range.first.is_valid() and
            &m_cache_range.first.buffer() == &buf and
            buf.timestamp() == m_cache_timestamp and
            range.first >= m_cache_range.first and
            range.second <= m_cache_range.second)
           return;

        m_cache_matches.clear();
        m_cache_range.first  = buf.iterator_at_line_begin(range.first.line() - 10);
        m_cache_range.second = buf.iterator_at_line_end(range.second.line() + 10);
        m_cache_timestamp = buf.timestamp();

        RegexIterator re_it(m_cache_range.first, m_cache_range.second, m_regex);
        RegexIterator re_end;
        for (; re_it != re_end; ++re_it)
            m_cache_matches.push_back(*re_it);
    }
};

HighlighterAndId colorize_regex_factory(const HighlighterParameters params)
{
    if (params.size() < 2)
        throw runtime_error("wrong parameter count");

    try
    {
        static Regex color_spec_ex(R"((\d+):(\w+(,\w+)?))");
        ColorSpec colors;
        for (auto it = params.begin() + 1;  it != params.end(); ++it)
        {
            boost::match_results<String::iterator> res;
            if (not boost::regex_match(it->begin(), it->end(), res, color_spec_ex))
                throw runtime_error("wrong colorspec: '" + *it +
                                     "' expected <capture>:<fgcolor>[,<bgcolor>]");

            int capture = str_to_int(String(res[1].first, res[1].second));
            const ColorPair*& color = colors[capture];
            color = &ColorRegistry::instance()[String(res[2].first, res[2].second)];
        }

        String id = "colre'" + params[0] + "'";

        Regex ex(params[0].begin(), params[0].end(),
                 boost::regex::perl | boost::regex::optimize);

        return HighlighterAndId(id, RegexColorizer(std::move(ex),
                                                   std::move(colors)));
    }
    catch (boost::regex_error& err)
    {
        throw runtime_error(String("regex error: ") + err.what());
    }
}

class SearchHighlighter
{
public:
    SearchHighlighter(const ColorSpec& colors)
        : m_colors(colors), m_colorizer(Regex(), m_colors) {}

    void operator()(DisplayBuffer& display_buffer)
    {
        memoryview<String> searches = RegisterManager::instance()['/'].values(Context{});
        if (searches.empty())
            return;
        const String& search = searches[0];
        if (search != m_last_search)
        {
            m_last_search = search;
            if (not m_last_search.empty())
                m_colorizer = RegexColorizer{Regex{m_last_search.begin(), m_last_search.end()}, m_colors};
        }
        if (not m_last_search.empty())
            m_colorizer(display_buffer);
    }

private:
    String         m_last_search;
    ColorSpec      m_colors;
    RegexColorizer m_colorizer;
};

HighlighterAndId highlight_search_factory(const HighlighterParameters params)
{
    if (params.size() != 1)
        throw runtime_error("wrong parameter count");
    try
    {
        ColorSpec colors;
        colors[0] = &ColorRegistry::instance()[params[0]];
        return {"hlsearch", SearchHighlighter{colors}};
    }
    catch (boost::regex_error& err)
    {
        throw runtime_error(String("regex error: ") + err.what());
    }
};

void expand_tabulations(const OptionManager& options, DisplayBuffer& display_buffer)
{
    const int tabstop = options["tabstop"].as_int();
    for (auto& line : display_buffer.lines())
    {
        for (auto atom_it = line.begin(); atom_it != line.end(); ++atom_it)
        {
            if (atom_it->content.type() != AtomContent::BufferRange)
                continue;

            auto begin = atom_it->content.begin();
            auto end = atom_it->content.end();
            for (BufferIterator it = begin; it != end; ++it)
            {
                if (*it == '\t')
                {
                    if (it != begin)
                        atom_it = ++line.split(atom_it, it);
                    if (it+1 != end)
                        atom_it = line.split(atom_it, it+1);

                    int column = 0;
                    for (auto line_it = it.buffer().iterator_at_line_begin(it);
                         line_it != it; ++line_it)
                    {
                        assert(*line_it != '\n');
                        if (*line_it == '\t')
                            column += tabstop - (column % tabstop);
                        else
                           ++column;
                    }

                    int count = tabstop - (column % tabstop);
                    String padding;
                    for (int i = 0; i < count; ++i)
                        padding += ' ';
                    atom_it->content.replace(padding);
                    break;
                }
            }
        }
    }
}

void show_line_numbers(DisplayBuffer& display_buffer)
{
    LineCount last_line = display_buffer.range().first.buffer().line_count();
    int digit_count = 0;
    for (LineCount c = last_line; c > 0; c /= 10)
        ++digit_count;

    char format[] = "%?d ";
    format[1] = '0' + digit_count;

    for (auto& line : display_buffer.lines())
    {
        char buffer[10];
        snprintf(buffer, 10, format, (int)line.buffer_line() + 1);
        DisplayAtom atom = DisplayAtom(AtomContent(buffer));
        atom.fg_color = Color::Black;
        atom.bg_color = Color::White;
        line.insert(line.begin(), std::move(atom));
    }
}

void highlight_selections(const SelectionList& selections, DisplayBuffer& display_buffer)
{
    for (auto& sel : selections)
    {
        highlight_range(display_buffer, sel.begin(), sel.end(), false,
                        [](DisplayAtom& atom) { atom.attribute |= Attributes::Underline; });

        const BufferIterator& last = sel.last();
        highlight_range(display_buffer, last, utf8::next(last), false,
                        [](DisplayAtom& atom) { atom.attribute |= Attributes::Reverse;
                                                atom.attribute &= ~Attributes::Underline; });
    }
    const Selection& back = selections.back();
    highlight_range(display_buffer, back.begin(), back.end(), false,
                    [](DisplayAtom& atom) { atom.attribute |= Attributes::Bold; });
}

void expand_unprintable(DisplayBuffer& display_buffer)
{
    for (auto& line : display_buffer.lines())
    {
        for (auto& atom : line)
        {
            if (atom.content.type() == AtomContent::BufferRange)
            {
                using Utf8It = utf8::utf8_iterator<BufferIterator>;
                for (Utf8It it = atom.content.begin(), end = atom.content.end(); it != end; ++it)
                {
                    Codepoint cp = *it;
                    if (cp != '\n' and not std::isprint((wchar_t)cp, std::locale()))
                    {
                        std::ostringstream oss;
                        oss << "U+" << std::hex << cp;
                        String str = oss.str();
                        highlight_range(display_buffer,
                                        it.underlying_iterator(), (it+1).underlying_iterator(),
                                        true, [&str](DisplayAtom& atom){ atom.content.replace(str);
                                                                         atom.bg_color = Color::Red;
                                                                         atom.fg_color = Color::Black; });
                    }
                }
            }
        }
    }
}

template<void (*highlighter_func)(DisplayBuffer&)>
class SimpleHighlighterFactory
{
public:
    SimpleHighlighterFactory(const String& id) : m_id(id) {}

    HighlighterAndId operator()(const HighlighterParameters& params) const
    {
        return HighlighterAndId(m_id, HighlighterFunc(highlighter_func));
    }
private:
    String m_id;
};

HighlighterAndId highlighter_group_factory(const HighlighterParameters& params)
{
    if (params.size() != 1)
        throw runtime_error("wrong parameter count");

    return HighlighterAndId(params[0], HighlighterGroup());
}

void register_highlighters()
{
    HighlighterRegistry& registry = HighlighterRegistry::instance();

    registry.register_func("number_lines", SimpleHighlighterFactory<show_line_numbers>("number_lines"));
    registry.register_func("regex", colorize_regex_factory);
    registry.register_func("search", highlight_search_factory);
    registry.register_func("group", highlighter_group_factory);
}

}
<commit_msg>Use colors instead of underline to highlight selections<commit_after>#include "highlighters.hh"
#include "assert.hh"
#include "color_registry.hh"
#include "highlighter_group.hh"
#include "register_manager.hh"
#include "context.hh"
#include "string.hh"
#include "utf8.hh"
#include "utf8_iterator.hh"

#include <sstream>
#include <locale>

namespace Kakoune
{

using namespace std::placeholders;

typedef boost::regex_iterator<BufferIterator> RegexIterator;

template<typename T>
void highlight_range(DisplayBuffer& display_buffer,
                     BufferIterator begin, BufferIterator end,
                     bool skip_replaced, T func)
{
    if (begin == end or end <= display_buffer.range().first
                     or begin >= display_buffer.range().second)
        return;

    for (auto& line : display_buffer.lines())
    {
        if (line.buffer_line() < begin.line() or  end.line() < line.buffer_line())
            continue;

        for (auto atom_it = line.begin(); atom_it != line.end(); ++atom_it)
        {
            bool is_replaced = atom_it->content.type() == AtomContent::ReplacedBufferRange;

            if (not atom_it->content.has_buffer_range() or
                (skip_replaced and is_replaced))
                continue;

            if (end <= atom_it->content.begin() or begin >= atom_it->content.end())
                continue;

            if (not is_replaced and begin > atom_it->content.begin())
                atom_it = ++line.split(atom_it, begin);

            if (not is_replaced and end < atom_it->content.end())
            {
                atom_it = line.split(atom_it, end);
                func(*atom_it);
                ++atom_it;
            }
            else
                func(*atom_it);
        }
    }
}

typedef std::unordered_map<size_t, const ColorPair*> ColorSpec;

class RegexColorizer
{
public:
    RegexColorizer(Regex regex, ColorSpec colors)
        : m_regex(std::move(regex)), m_colors(std::move(colors)),
          m_cache_timestamp(0)
    {
    }

    void operator()(DisplayBuffer& display_buffer)
    {
        update_cache_ifn(display_buffer.range());
        for (auto& match : m_cache_matches)
        {
            for (size_t n = 0; n < match.size(); ++n)
            {
                auto col_it = m_colors.find(n);
                if (col_it == m_colors.end())
                    continue;

                highlight_range(display_buffer, match[n].first, match[n].second, true,
                                [&](DisplayAtom& atom) {
                                    atom.fg_color = col_it->second->first;
                                    atom.bg_color = col_it->second->second;
                                });
            }
        }
    }

private:
    BufferRange m_cache_range;
    size_t      m_cache_timestamp;
    std::vector<boost::match_results<BufferIterator>> m_cache_matches;

    Regex     m_regex;
    ColorSpec m_colors;

    void update_cache_ifn(const BufferRange& range)
    {
        const Buffer& buf = range.first.buffer();
        if (m_cache_range.first.is_valid() and
            &m_cache_range.first.buffer() == &buf and
            buf.timestamp() == m_cache_timestamp and
            range.first >= m_cache_range.first and
            range.second <= m_cache_range.second)
           return;

        m_cache_matches.clear();
        m_cache_range.first  = buf.iterator_at_line_begin(range.first.line() - 10);
        m_cache_range.second = buf.iterator_at_line_end(range.second.line() + 10);
        m_cache_timestamp = buf.timestamp();

        RegexIterator re_it(m_cache_range.first, m_cache_range.second, m_regex);
        RegexIterator re_end;
        for (; re_it != re_end; ++re_it)
            m_cache_matches.push_back(*re_it);
    }
};

HighlighterAndId colorize_regex_factory(const HighlighterParameters params)
{
    if (params.size() < 2)
        throw runtime_error("wrong parameter count");

    try
    {
        static Regex color_spec_ex(R"((\d+):(\w+(,\w+)?))");
        ColorSpec colors;
        for (auto it = params.begin() + 1;  it != params.end(); ++it)
        {
            boost::match_results<String::iterator> res;
            if (not boost::regex_match(it->begin(), it->end(), res, color_spec_ex))
                throw runtime_error("wrong colorspec: '" + *it +
                                     "' expected <capture>:<fgcolor>[,<bgcolor>]");

            int capture = str_to_int(String(res[1].first, res[1].second));
            const ColorPair*& color = colors[capture];
            color = &ColorRegistry::instance()[String(res[2].first, res[2].second)];
        }

        String id = "colre'" + params[0] + "'";

        Regex ex(params[0].begin(), params[0].end(),
                 boost::regex::perl | boost::regex::optimize);

        return HighlighterAndId(id, RegexColorizer(std::move(ex),
                                                   std::move(colors)));
    }
    catch (boost::regex_error& err)
    {
        throw runtime_error(String("regex error: ") + err.what());
    }
}

class SearchHighlighter
{
public:
    SearchHighlighter(const ColorSpec& colors)
        : m_colors(colors), m_colorizer(Regex(), m_colors) {}

    void operator()(DisplayBuffer& display_buffer)
    {
        memoryview<String> searches = RegisterManager::instance()['/'].values(Context{});
        if (searches.empty())
            return;
        const String& search = searches[0];
        if (search != m_last_search)
        {
            m_last_search = search;
            if (not m_last_search.empty())
                m_colorizer = RegexColorizer{Regex{m_last_search.begin(), m_last_search.end()}, m_colors};
        }
        if (not m_last_search.empty())
            m_colorizer(display_buffer);
    }

private:
    String         m_last_search;
    ColorSpec      m_colors;
    RegexColorizer m_colorizer;
};

HighlighterAndId highlight_search_factory(const HighlighterParameters params)
{
    if (params.size() != 1)
        throw runtime_error("wrong parameter count");
    try
    {
        ColorSpec colors;
        colors[0] = &ColorRegistry::instance()[params[0]];
        return {"hlsearch", SearchHighlighter{colors}};
    }
    catch (boost::regex_error& err)
    {
        throw runtime_error(String("regex error: ") + err.what());
    }
};

void expand_tabulations(const OptionManager& options, DisplayBuffer& display_buffer)
{
    const int tabstop = options["tabstop"].as_int();
    for (auto& line : display_buffer.lines())
    {
        for (auto atom_it = line.begin(); atom_it != line.end(); ++atom_it)
        {
            if (atom_it->content.type() != AtomContent::BufferRange)
                continue;

            auto begin = atom_it->content.begin();
            auto end = atom_it->content.end();
            for (BufferIterator it = begin; it != end; ++it)
            {
                if (*it == '\t')
                {
                    if (it != begin)
                        atom_it = ++line.split(atom_it, it);
                    if (it+1 != end)
                        atom_it = line.split(atom_it, it+1);

                    int column = 0;
                    for (auto line_it = it.buffer().iterator_at_line_begin(it);
                         line_it != it; ++line_it)
                    {
                        assert(*line_it != '\n');
                        if (*line_it == '\t')
                            column += tabstop - (column % tabstop);
                        else
                           ++column;
                    }

                    int count = tabstop - (column % tabstop);
                    String padding;
                    for (int i = 0; i < count; ++i)
                        padding += ' ';
                    atom_it->content.replace(padding);
                    break;
                }
            }
        }
    }
}

void show_line_numbers(DisplayBuffer& display_buffer)
{
    LineCount last_line = display_buffer.range().first.buffer().line_count();
    int digit_count = 0;
    for (LineCount c = last_line; c > 0; c /= 10)
        ++digit_count;

    char format[] = "%?d ";
    format[1] = '0' + digit_count;

    for (auto& line : display_buffer.lines())
    {
        char buffer[10];
        snprintf(buffer, 10, format, (int)line.buffer_line() + 1);
        DisplayAtom atom = DisplayAtom(AtomContent(buffer));
        atom.fg_color = Color::Black;
        atom.bg_color = Color::White;
        line.insert(line.begin(), std::move(atom));
    }
}

void highlight_selections(const SelectionList& selections, DisplayBuffer& display_buffer)
{
    for (size_t i = 0; i < selections.size(); ++i)
    {
        auto& sel = selections[i];
        const bool forward = sel.first() <= sel.last();
        BufferIterator begin = forward ? sel.first() : utf8::next(sel.last());
        BufferIterator end   = forward ? sel.last() : utf8::next(sel.first());

        Color fg_color = (i == selections.size() - 1) ? Color::Cyan : Color::Black;
        Color bg_color = (i == selections.size() - 1) ? Color::Blue : Color::Blue;
        highlight_range(display_buffer, begin, end, false,
                        [&](DisplayAtom& atom) { atom.fg_color = fg_color; atom.bg_color = bg_color; });
        highlight_range(display_buffer, sel.last(), utf8::next(sel.last()), false,
                        [](DisplayAtom& atom) { atom.fg_color = Color::Black; atom.bg_color = Color::White; });
    }
}

void expand_unprintable(DisplayBuffer& display_buffer)
{
    for (auto& line : display_buffer.lines())
    {
        for (auto& atom : line)
        {
            if (atom.content.type() == AtomContent::BufferRange)
            {
                using Utf8It = utf8::utf8_iterator<BufferIterator>;
                for (Utf8It it = atom.content.begin(), end = atom.content.end(); it != end; ++it)
                {
                    Codepoint cp = *it;
                    if (cp != '\n' and not std::isprint((wchar_t)cp, std::locale()))
                    {
                        std::ostringstream oss;
                        oss << "U+" << std::hex << cp;
                        String str = oss.str();
                        highlight_range(display_buffer,
                                        it.underlying_iterator(), (it+1).underlying_iterator(),
                                        true, [&str](DisplayAtom& atom){ atom.content.replace(str);
                                                                         atom.bg_color = Color::Red;
                                                                         atom.fg_color = Color::Black; });
                    }
                }
            }
        }
    }
}

template<void (*highlighter_func)(DisplayBuffer&)>
class SimpleHighlighterFactory
{
public:
    SimpleHighlighterFactory(const String& id) : m_id(id) {}

    HighlighterAndId operator()(const HighlighterParameters& params) const
    {
        return HighlighterAndId(m_id, HighlighterFunc(highlighter_func));
    }
private:
    String m_id;
};

HighlighterAndId highlighter_group_factory(const HighlighterParameters& params)
{
    if (params.size() != 1)
        throw runtime_error("wrong parameter count");

    return HighlighterAndId(params[0], HighlighterGroup());
}

void register_highlighters()
{
    HighlighterRegistry& registry = HighlighterRegistry::instance();

    registry.register_func("number_lines", SimpleHighlighterFactory<show_line_numbers>("number_lines"));
    registry.register_func("regex", colorize_regex_factory);
    registry.register_func("search", highlight_search_factory);
    registry.register_func("group", highlighter_group_factory);
}

}
<|endoftext|>


<commit_before>/*
 * Written by Nitin Kumar Maharana
 * nitin.maharana@gmail.com
 */

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
    int findLength(ListNode* head)
    {
        int len = 0;

        while(head)
        {
            len++;
            head = head->next;
        }

        return len;
    }

    void advancePointer(ListNode **ptr, int len)
    {
        while(len--)
            (*ptr) = (*ptr)->next;
    }

public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {

        if(!headA || !headB)
            return NULL;

        int lenA, lenB;

        lenA = findLength(headA);
        lenB = findLength(headB);

        ListNode *ptrA, *ptrB;

        ptrA = headA;
        ptrB = headB;

        (lenA < lenB) ? advancePointer(&ptrB, lenB-lenA) : advancePointer(&ptrA, lenA-lenB);

        while(ptrA && ptrB)
        {
            if(ptrA == ptrB)
                return ptrA;

            ptrA = ptrA->next;
            ptrB = ptrB->next;
        }

        return NULL;
    }
};<commit_msg>160. Intersection of Two Linked Lists<commit_after>/*
 * Written by Nitin Kumar Maharana
 * nitin.maharana@gmail.com
 */

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
    int findLength(ListNode* head)
    {
        int len = 0;

        while(head)
        {
            len++;
            head = head->next;
        }

        return len;
    }

    void advancePointer(ListNode **ptr, int len)
    {
        while(len--)
            (*ptr) = (*ptr)->next;
    }

public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {

        if(!headA || !headB)
            return nullptr;

        int lenA, lenB;

        lenA = findLength(headA);
        lenB = findLength(headB);

        ListNode *ptrA, *ptrB;

        ptrA = headA;
        ptrB = headB;

        (lenA < lenB) ? advancePointer(&ptrB, lenB-lenA) : advancePointer(&ptrA, lenA-lenB);

        while(ptrA && ptrB)
        {
            if(ptrA == ptrB)
                return ptrA;

            ptrA = ptrA->next;
            ptrB = ptrB->next;
        }

        return nullptr;
    }
};
<|endoftext|>


<commit_before>/*
 *  mcsignal_main.cpp
 *
 *  Created by Tobias Wood on 12/11/2012.
 *  Copyright (c) 2013 Tobias Wood.
 *
 *  This Source Code Form is subject to the terms of the Mozilla Public
 *  License, v. 2.0. If a copy of the MPL was not distributed with this
 *  file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 */

#include <string>
#include <iostream>
#include <getopt.h>
#include <exception>
#include <Eigen/Dense>

#include "itkImageFileReader.h"
#include "itkImageFileWriter.h"
#include "itkVectorImage.h"
#include "itkImageToImageFilter.h"
#include "itkComplexToModulusImageFilter.h"

#include "Filters/VectorToImageFilter.h"

#include "Model.h"
#include "Sequence.h"
#include "Util.h"

using namespace std;
using namespace Eigen;
using namespace QUITK;

//******************************************************************************
// Filter
//******************************************************************************
typedef itk::Image<float, 3> TImage;
typedef itk::VectorImage<float, 3> TVImage;
typedef itk::VectorImage<complex<float>, 3> TCVImage;

class SignalsFilter : public itk::ImageToImageFilter<TImage, TCVImage> {
private:
	shared_ptr<SequenceBase> m_sequence;
	shared_ptr<Model> m_model;

public:
	/** Standard class typedefs. */
	typedef SignalsFilter                        Self;
	typedef ImageToImageFilter<TImage, TCVImage> Superclass;
	typedef itk::SmartPointer<Self>                   Pointer;
	typedef typename TImage::RegionType          RegionType;

	itkNewMacro(Self); /** Method for creation through the object factory. */
	itkTypeMacro(Self, Superclass); /** Run-time type information (and related methods). */

	void SetInput(const size_t i, const TImage *img) {
		//std::cout <<  __PRETTY_FUNCTION__ << endl;
		if (i < m_model->nParameters()) {
			this->SetNthInput(i, const_cast<TImage*>(img));
		} else {
			throw(runtime_error("Const input out of range"));
		}
	}
	void SetMask(const TImage *mask) {
		//std::cout <<  __PRETTY_FUNCTION__ << endl;
		this->SetNthInput(m_model->nParameters(), const_cast<TImage*>(mask));
	}

	typename TImage::ConstPointer GetInput(const size_t i) const {
		//std::cout <<  __PRETTY_FUNCTION__ << endl;
		if (i < m_model->nParameters()) {
			return static_cast<const TImage *> (this->ProcessObject::GetInput(i));
		} else {
			throw(runtime_error("Get Data Input out of range."));
		}
	}

	typename TImage::ConstPointer GetMask() const {
		//std::cout <<  __PRETTY_FUNCTION__ << endl;
		return static_cast<const TImage *>(this->ProcessObject::GetInput(m_model->nParameters()));
	}

	TCVImage *GetOutput() {
		//std::cout <<  __PRETTY_FUNCTION__ << endl;
		return dynamic_cast<TCVImage *>(this->ProcessObject::GetOutput(0));
	}

	void SetSequence(shared_ptr<SequenceBase> s) {
		m_sequence = s;
		this->SetNumberOfRequiredOutputs(1);
		this->SetNthOutput(0, this->MakeOutput(0));
	}
	void SetModel(shared_ptr<Model> m) {
		m_model = m;
		this->SetNumberOfRequiredInputs(m_model->nParameters());
	}

	virtual void GenerateOutputInformation() override {
		//std::cout <<  __PRETTY_FUNCTION__ << endl;
		Superclass::GenerateOutputInformation();
		const auto op = this->GetOutput();
		op->SetRegions(this->GetInput(0)->GetLargestPossibleRegion());
		op->SetNumberOfComponentsPerPixel(m_sequence->size());
		op->Allocate();
	}

	virtual void Update() override {
		//std::cout << __PRETTY_FUNCTION__ << endl;
		Superclass::Update();
	}

protected:
	SignalsFilter() {}
	~SignalsFilter(){}

	virtual void ThreadedGenerateData(const RegionType &region, itk::ThreadIdType threadId) {
		//std::cout <<  __PRETTY_FUNCTION__ << endl;
		vector<itk::ImageRegionConstIterator<TImage>> inIters(m_model->nParameters());
		for (size_t i = 0; i < m_model->nParameters(); i++) {
			inIters[i] = itk::ImageRegionConstIterator<TImage>(this->GetInput(i), region);
		}
		itk::ImageRegionConstIterator<TImage> maskIter;
		if (this->GetMask()) {
			maskIter = itk::ImageRegionConstIterator<TImage>(this->GetMask(), region);
		}
		itk::ImageRegionIterator<TCVImage> outputIter(this->GetOutput(), region);
		while(!inIters[0].IsAtEnd()) {
			typename TImage::ConstPointer m = this->GetMask();
			if (!m || maskIter.Get()) {
				VectorXd parameters(m_model->nParameters());
				for (size_t i = 0; i < inIters.size(); i++) {
					parameters[i] = inIters[i].Get();
				}
				VectorXcf allData = m_sequence->signal(m_model, parameters).cast<complex<float>>();
				itk::VariableLengthVector<complex<float>> dataVector(allData.data(), m_sequence->size());
				outputIter.Set(dataVector);
			}
			if (this->GetMask())
				++maskIter;
			for (size_t i = 0; i < m_model->nParameters(); i++) {
					++inIters[i];
			}
			++outputIter;
		}
	}

	itk::DataObject::Pointer MakeOutput(unsigned int idx) {
		//std::cout <<  __PRETTY_FUNCTION__ << endl;
		itk::DataObject::Pointer output;
		if (idx < 1) {
			auto img = TCVImage::New();
			img->SetNumberOfComponentsPerPixel(m_sequence->size());
			output = img;
		} else {
			std::cerr << "No output " << idx << std::endl;
			output = NULL;
		}
		return output.GetPointer();
	}

private:
	SignalsFilter(const Self &); //purposely not implemented
	void operator=(const Self &);  //purposely not implemented
};

//******************************************************************************
// Arguments / Usage
//******************************************************************************
const string usage {
"Usage is: mcsignal [options]\n\
\n\
Calculates multi-component DESPOT signals (mainly for testing purposes).\n\
The program will prompt for input (unless --no-prompt specified)\n\
\n\
All times (TR) are in SECONDS. All angles are in degrees.\n\
\n\
Options:\n\
	--help, -h        : Print this message.\n\
	--verbose, -v     : Print extra information.\n\
	--mask, -m file   : Only calculate inside the mask.\n\
	--out, -o path    : Add a prefix to the output filenames\n\
	--no-prompt, -n   : Don't print prompts for input.\n\
	--noise, -N val   : Add complex noise with std=val.\n\
	--1, --2, --3     : Use 1, 2 or 3 component sequences (default 3).\n\
	--complex, -x     : Output complex-valued signal.\n\
	--sequences, -M s : Use simple sequences (default).\n\
	            f     : Use Finite Pulse Length correction.\n\
	--threads, -T N   : Use N threads (default=hardware limit)\n"
};

static shared_ptr<Model> model = make_shared<SCD>();
static bool verbose = false, prompt = true, finitesequences = false, outputComplex = false;
static string outPrefix = "";
static double sigma = 0.;
static struct option long_opts[] = {
	{"help", no_argument, 0, 'h'},
	{"verbose", no_argument, 0, 'v'},
	{"mask", required_argument, 0, 'm'},
	{"out", required_argument, 0, 'o'},
	{"no-prompt", no_argument, 0, 'n'},
	{"noise", required_argument, 0, 'N'},
	{"1", no_argument, 0, '1'},
	{"2", no_argument, 0, '2'},
	{"3", no_argument, 0, '3'},
	{"complex", no_argument, 0, 'x'},
	{"sequences", no_argument, 0, 'M'},
	{"threads", required_argument, 0, 'T'},
	{0, 0, 0, 0}
};
static const char *short_opts = "hvnN:m:o:123xM:T:";
//******************************************************************************
#pragma mark Read in all required files and data from cin
//******************************************************************************
void parseInput(vector<shared_ptr<SequenceBase>> &cs, vector<string> &names);
void parseInput(vector<shared_ptr<SequenceBase>> &cs, vector<string> &names) {
	string type;
	if (prompt) cout << "Specify next signal type (SPGR/SSFP): " << flush;
	while (Read(cin, type) && (type != "END") && (type != "")) {
		if (type == "SPGR") {
			cs.push_back(make_shared<SPGRSimple>(prompt));
		} else if (type == "SPGRFinite") {
			cs.push_back(make_shared<SPGRFinite>(prompt));
		} else if (type == "SSFP") {
			cs.push_back(make_shared<SSFPSimple>(prompt));
		} else if (type == "SSFPFinite") {
			cs.push_back(make_shared<SSFPFinite>(prompt));
		} else if (type == "SSFPEllipse") {
			cs.push_back(make_shared<SSFPEllipse>(prompt));
		} else if (type == "IRSPGR") {
			cs.push_back(make_shared<IRSPGR>(prompt));
		} else if (type == "MPRAGE") {
			cs.push_back(make_shared<MPRAGE>(prompt));
		} else if (type == "SPINECHO") {
			cs.push_back(make_shared<MultiEcho>(prompt));
		} else {
			throw(std::runtime_error("Unknown signal type: " + type));
		}
		string filename;
		if (prompt) cout << "Enter output filename: " << flush;
		Read(cin, filename);
		names.push_back(filename);
		// Print message ready for next loop
		if (prompt) cout << "Specify next image type (SPGR/SSFP, END to finish input): " << flush;
	}
}
//******************************************************************************
// Main
//******************************************************************************
int main(int argc, char **argv)
{
	Eigen::initParallel();

	try { // To fix uncaught exceptions on Mac

	typedef itk::Image<float, 3> FloatImage;
	typedef itk::VectorImage<float, 3> FloatVectorImage;

	typedef itk::ImageFileReader<FloatImage> Reader;

	Reader::Pointer mask = ITK_NULLPTR;
	int indexptr = 0, c;
	while ((c = getopt_long(argc, argv, short_opts, long_opts, &indexptr)) != -1) {
		switch (c) {
			case 'v': verbose = true; break;
			case 'n': prompt = false; break;
			case 'N': sigma = atof(optarg); break;
			case 'm':
				cout << "Reading mask file " << optarg << endl;
				mask = Reader::New();
				mask->SetFileName(optarg);
				break;
			case 'o':
				outPrefix = optarg;
				cout << "Output prefix will be: " << outPrefix << endl;
				break;
			case '1': model = make_shared<SCD>(); break;
			case '2': model = make_shared<MCD2>(); break;
			case '3': model = make_shared<MCD3>(); break;
			case 'x': outputComplex = true; break;
			case 'M':
				switch (*optarg) {
					case 's': finitesequences = false; if (prompt) cout << "Simple sequences selected." << endl; break;
					case 'f': finitesequences = true; if (prompt) cout << "Finite pulse correction selected." << endl; break;
					default:
						cout << "Unknown sequences type " << *optarg << endl;
						return EXIT_FAILURE;
						break;
				}
				break;
			case 'T':
				itk::MultiThreader::SetGlobalDefaultNumberOfThreads(atoi(optarg));
				break;
			case 'h':
			case '?': // getopt will print an error message
			default:
				cout << usage << endl;
				return EXIT_FAILURE;
		}
	}
	if ((argc - optind) != 0) {
		cerr << usage << endl << "Incorrect number of arguments." << endl;
		return EXIT_FAILURE;
	}
	//if (verbose) cout << version << endl << credit_me << endl;
	if (verbose) cout << "Using " << model->Name() << " model." << endl;
	/***************************************************************************
	 * Read in parameter files
	 **************************************************************************/
	SignalsFilter::Pointer calcSignal = SignalsFilter::New();
	calcSignal->SetModel(model);
	vector<Reader::Pointer> pFiles(model->nParameters());
	if (prompt) cout << "Loading parameters." << endl;
	for (size_t i = 0; i < model->nParameters(); i++) {
		if (prompt) cout << "Enter path to " << model->Names()[i] << " file: " << flush;
		string filename;
		getline(cin, filename);
		if (verbose) cout << "Opening " << filename << endl;
		pFiles[i] = Reader::New();
		pFiles[i]->SetFileName(filename);
		calcSignal->SetInput(i, pFiles[i]->GetOutput());
	}

	/***************************************************************************
	 * Set up sequences
	 **************************************************************************/
	vector<shared_ptr<SequenceBase>> sequences;
	vector<string> filenames;
	parseInput(sequences, filenames);
	for (size_t i = 0; i < sequences.size(); i++) {
		if (verbose) {
			cout << "Calculating sequence: " << endl << *(sequences[i]);
		}
		calcSignal->SetSequence(sequences[i]);
		auto VecTo4D = VectorToImageFilter<complex<float>>::New();
		VecTo4D->SetInput(calcSignal->GetOutput());
		if (outputComplex) {
			auto writer = itk::ImageFileWriter<itk::Image<complex<float>,4>>::New();
			writer->SetInput(VecTo4D->GetOutput());
			writer->SetFileName(filenames[i]);
			writer->Update();
		} else {
			auto writer = itk::ImageFileWriter<itk::Image<float, 4>>::New();
			auto abs = itk::ComplexToModulusImageFilter<itk::Image<complex<float>, 4>, itk::Image<float, 4>>::New();
			abs->SetInput(VecTo4D->GetOutput());
			writer->SetInput(abs->GetOutput());
			writer->SetFileName(filenames[i]);
			writer->Update();
		}
	}
	if (verbose) cout << "Finished all sequences." << endl;
	} catch (exception &e) {
		cerr << e.what() << endl;
		return EXIT_FAILURE;
	}
	return EXIT_SUCCESS;
}

<commit_msg>Added a missing namespace.<commit_after>/*
 *  mcsignal_main.cpp
 *
 *  Created by Tobias Wood on 12/11/2012.
 *  Copyright (c) 2013 Tobias Wood.
 *
 *  This Source Code Form is subject to the terms of the Mozilla Public
 *  License, v. 2.0. If a copy of the MPL was not distributed with this
 *  file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 */

#include <string>
#include <iostream>
#include <getopt.h>
#include <exception>
#include <Eigen/Dense>

#include "itkImageFileReader.h"
#include "itkImageFileWriter.h"
#include "itkVectorImage.h"
#include "itkImageToImageFilter.h"
#include "itkComplexToModulusImageFilter.h"

#include "Filters/VectorToImageFilter.h"

#include "Model.h"
#include "Sequence.h"
#include "Util.h"

using namespace std;
using namespace Eigen;
using namespace QUITK;

//******************************************************************************
// Filter
//******************************************************************************
typedef itk::Image<float, 3> TImage;
typedef itk::VectorImage<float, 3> TVImage;
typedef itk::VectorImage<complex<float>, 3> TCVImage;

class SignalsFilter : public itk::ImageToImageFilter<TImage, TCVImage> {
private:
	shared_ptr<SequenceBase> m_sequence;
	shared_ptr<Model> m_model;

public:
	/** Standard class typedefs. */
	typedef SignalsFilter                        Self;
	typedef ImageToImageFilter<TImage, TCVImage> Superclass;
	typedef itk::SmartPointer<Self>                   Pointer;
	typedef typename TImage::RegionType          RegionType;

	itkNewMacro(Self); /** Method for creation through the object factory. */
	itkTypeMacro(Self, Superclass); /** Run-time type information (and related methods). */

	void SetInput(const size_t i, const TImage *img) {
		//std::cout <<  __PRETTY_FUNCTION__ << endl;
		if (i < m_model->nParameters()) {
			this->SetNthInput(i, const_cast<TImage*>(img));
		} else {
			throw(runtime_error("Const input out of range"));
		}
	}
	void SetMask(const TImage *mask) {
		//std::cout <<  __PRETTY_FUNCTION__ << endl;
		this->SetNthInput(m_model->nParameters(), const_cast<TImage*>(mask));
	}

	typename TImage::ConstPointer GetInput(const size_t i) const {
		//std::cout <<  __PRETTY_FUNCTION__ << endl;
		if (i < m_model->nParameters()) {
			return static_cast<const TImage *> (this->ProcessObject::GetInput(i));
		} else {
			throw(runtime_error("Get Data Input out of range."));
		}
	}

	typename TImage::ConstPointer GetMask() const {
		//std::cout <<  __PRETTY_FUNCTION__ << endl;
		return static_cast<const TImage *>(this->ProcessObject::GetInput(m_model->nParameters()));
	}

	TCVImage *GetOutput() {
		//std::cout <<  __PRETTY_FUNCTION__ << endl;
		return dynamic_cast<TCVImage *>(this->ProcessObject::GetOutput(0));
	}

	void SetSequence(shared_ptr<SequenceBase> s) {
		m_sequence = s;
		this->SetNumberOfRequiredOutputs(1);
		this->SetNthOutput(0, this->MakeOutput(0));
	}
	void SetModel(shared_ptr<Model> m) {
		m_model = m;
		this->SetNumberOfRequiredInputs(m_model->nParameters());
	}

	virtual void GenerateOutputInformation() override {
		//std::cout <<  __PRETTY_FUNCTION__ << endl;
		Superclass::GenerateOutputInformation();
		const auto op = this->GetOutput();
		op->SetRegions(this->GetInput(0)->GetLargestPossibleRegion());
		op->SetNumberOfComponentsPerPixel(m_sequence->size());
		op->Allocate();
	}

	virtual void Update() override {
		//std::cout << __PRETTY_FUNCTION__ << endl;
		Superclass::Update();
	}

protected:
	SignalsFilter() {}
	~SignalsFilter(){}

	virtual void ThreadedGenerateData(const RegionType &region, itk::ThreadIdType threadId) {
		//std::cout <<  __PRETTY_FUNCTION__ << endl;
		vector<itk::ImageRegionConstIterator<TImage>> inIters(m_model->nParameters());
		for (size_t i = 0; i < m_model->nParameters(); i++) {
			inIters[i] = itk::ImageRegionConstIterator<TImage>(this->GetInput(i), region);
		}
		itk::ImageRegionConstIterator<TImage> maskIter;
		if (this->GetMask()) {
			maskIter = itk::ImageRegionConstIterator<TImage>(this->GetMask(), region);
		}
		itk::ImageRegionIterator<TCVImage> outputIter(this->GetOutput(), region);
		while(!inIters[0].IsAtEnd()) {
			typename TImage::ConstPointer m = this->GetMask();
			if (!m || maskIter.Get()) {
				VectorXd parameters(m_model->nParameters());
				for (size_t i = 0; i < inIters.size(); i++) {
					parameters[i] = inIters[i].Get();
				}
				VectorXcf allData = m_sequence->signal(m_model, parameters).cast<complex<float>>();
				itk::VariableLengthVector<complex<float>> dataVector(allData.data(), m_sequence->size());
				outputIter.Set(dataVector);
			}
			if (this->GetMask())
				++maskIter;
			for (size_t i = 0; i < m_model->nParameters(); i++) {
					++inIters[i];
			}
			++outputIter;
		}
	}

	itk::DataObject::Pointer MakeOutput(unsigned int idx) {
		//std::cout <<  __PRETTY_FUNCTION__ << endl;
		itk::DataObject::Pointer output;
		if (idx < 1) {
			auto img = TCVImage::New();
			img->SetNumberOfComponentsPerPixel(m_sequence->size());
			output = img;
		} else {
			std::cerr << "No output " << idx << std::endl;
			output = NULL;
		}
		return output.GetPointer();
	}

private:
	SignalsFilter(const Self &); //purposely not implemented
	void operator=(const Self &);  //purposely not implemented
};

//******************************************************************************
// Arguments / Usage
//******************************************************************************
const string usage {
"Usage is: mcsignal [options]\n\
\n\
Calculates multi-component DESPOT signals (mainly for testing purposes).\n\
The program will prompt for input (unless --no-prompt specified)\n\
\n\
All times (TR) are in SECONDS. All angles are in degrees.\n\
\n\
Options:\n\
	--help, -h        : Print this message.\n\
	--verbose, -v     : Print extra information.\n\
	--mask, -m file   : Only calculate inside the mask.\n\
	--out, -o path    : Add a prefix to the output filenames\n\
	--no-prompt, -n   : Don't print prompts for input.\n\
	--noise, -N val   : Add complex noise with std=val.\n\
	--1, --2, --3     : Use 1, 2 or 3 component sequences (default 3).\n\
	--complex, -x     : Output complex-valued signal.\n\
	--sequences, -M s : Use simple sequences (default).\n\
	            f     : Use Finite Pulse Length correction.\n\
	--threads, -T N   : Use N threads (default=hardware limit)\n"
};

static shared_ptr<Model> model = make_shared<SCD>();
static bool verbose = false, prompt = true, finitesequences = false, outputComplex = false;
static string outPrefix = "";
static double sigma = 0.;
static struct option long_opts[] = {
	{"help", no_argument, 0, 'h'},
	{"verbose", no_argument, 0, 'v'},
	{"mask", required_argument, 0, 'm'},
	{"out", required_argument, 0, 'o'},
	{"no-prompt", no_argument, 0, 'n'},
	{"noise", required_argument, 0, 'N'},
	{"1", no_argument, 0, '1'},
	{"2", no_argument, 0, '2'},
	{"3", no_argument, 0, '3'},
	{"complex", no_argument, 0, 'x'},
	{"sequences", no_argument, 0, 'M'},
	{"threads", required_argument, 0, 'T'},
	{0, 0, 0, 0}
};
static const char *short_opts = "hvnN:m:o:123xM:T:";
//******************************************************************************
#pragma mark Read in all required files and data from cin
//******************************************************************************
void parseInput(vector<shared_ptr<SequenceBase>> &cs, vector<string> &names);
void parseInput(vector<shared_ptr<SequenceBase>> &cs, vector<string> &names) {
	string type;
	if (prompt) cout << "Specify next signal type (SPGR/SSFP): " << flush;
	while (Read(cin, type) && (type != "END") && (type != "")) {
		if (type == "SPGR") {
			cs.push_back(make_shared<SPGRSimple>(prompt));
		} else if (type == "SPGRFinite") {
			cs.push_back(make_shared<SPGRFinite>(prompt));
		} else if (type == "SSFP") {
			cs.push_back(make_shared<SSFPSimple>(prompt));
		} else if (type == "SSFPFinite") {
			cs.push_back(make_shared<SSFPFinite>(prompt));
		} else if (type == "SSFPEllipse") {
			cs.push_back(make_shared<SSFPEllipse>(prompt));
		} else if (type == "IRSPGR") {
			cs.push_back(make_shared<IRSPGR>(prompt));
		} else if (type == "MPRAGE") {
			cs.push_back(make_shared<MPRAGE>(prompt));
		} else if (type == "SPINECHO") {
			cs.push_back(make_shared<MultiEcho>(prompt));
		} else {
			throw(std::runtime_error("Unknown signal type: " + type));
		}
		string filename;
		if (prompt) cout << "Enter output filename: " << flush;
		Read(cin, filename);
		names.push_back(filename);
		// Print message ready for next loop
		if (prompt) cout << "Specify next image type (SPGR/SSFP, END to finish input): " << flush;
	}
}
//******************************************************************************
// Main
//******************************************************************************
int main(int argc, char **argv)
{
	Eigen::initParallel();

	try { // To fix uncaught exceptions on Mac

	typedef itk::Image<float, 3> FloatImage;
	typedef itk::VectorImage<float, 3> FloatVectorImage;

	typedef itk::ImageFileReader<FloatImage> Reader;

	Reader::Pointer mask = ITK_NULLPTR;
	int indexptr = 0, c;
	while ((c = getopt_long(argc, argv, short_opts, long_opts, &indexptr)) != -1) {
		switch (c) {
			case 'v': verbose = true; break;
			case 'n': prompt = false; break;
			case 'N': sigma = atof(optarg); break;
			case 'm':
				cout << "Reading mask file " << optarg << endl;
				mask = Reader::New();
				mask->SetFileName(optarg);
				break;
			case 'o':
				outPrefix = optarg;
				cout << "Output prefix will be: " << outPrefix << endl;
				break;
			case '1': model = make_shared<SCD>(); break;
			case '2': model = make_shared<MCD2>(); break;
			case '3': model = make_shared<MCD3>(); break;
			case 'x': outputComplex = true; break;
			case 'M':
				switch (*optarg) {
					case 's': finitesequences = false; if (prompt) cout << "Simple sequences selected." << endl; break;
					case 'f': finitesequences = true; if (prompt) cout << "Finite pulse correction selected." << endl; break;
					default:
						cout << "Unknown sequences type " << *optarg << endl;
						return EXIT_FAILURE;
						break;
				}
				break;
			case 'T':
				itk::MultiThreader::SetGlobalDefaultNumberOfThreads(atoi(optarg));
				break;
			case 'h':
			case '?': // getopt will print an error message
			default:
				cout << usage << endl;
				return EXIT_FAILURE;
		}
	}
	if ((argc - optind) != 0) {
		cerr << usage << endl << "Incorrect number of arguments." << endl;
		return EXIT_FAILURE;
	}
	//if (verbose) cout << version << endl << credit_me << endl;
	if (verbose) cout << "Using " << model->Name() << " model." << endl;
	/***************************************************************************
	 * Read in parameter files
	 **************************************************************************/
	SignalsFilter::Pointer calcSignal = SignalsFilter::New();
	calcSignal->SetModel(model);
	vector<Reader::Pointer> pFiles(model->nParameters());
	if (prompt) cout << "Loading parameters." << endl;
	for (size_t i = 0; i < model->nParameters(); i++) {
		if (prompt) cout << "Enter path to " << model->Names()[i] << " file: " << flush;
		string filename;
		getline(cin, filename);
		if (verbose) cout << "Opening " << filename << endl;
		pFiles[i] = Reader::New();
		pFiles[i]->SetFileName(filename);
		calcSignal->SetInput(i, pFiles[i]->GetOutput());
	}

	/***************************************************************************
	 * Set up sequences
	 **************************************************************************/
	vector<shared_ptr<SequenceBase>> sequences;
	vector<string> filenames;
	parseInput(sequences, filenames);
	for (size_t i = 0; i < sequences.size(); i++) {
		if (verbose) {
			cout << "Calculating sequence: " << endl << *(sequences[i]);
		}
		calcSignal->SetSequence(sequences[i]);
		auto VecTo4D = itk::VectorToImageFilter<complex<float>>::New();
		VecTo4D->SetInput(calcSignal->GetOutput());
		if (outputComplex) {
			auto writer = itk::ImageFileWriter<itk::Image<complex<float>,4>>::New();
			writer->SetInput(VecTo4D->GetOutput());
			writer->SetFileName(filenames[i]);
			writer->Update();
		} else {
			auto writer = itk::ImageFileWriter<itk::Image<float, 4>>::New();
			auto abs = itk::ComplexToModulusImageFilter<itk::Image<complex<float>, 4>, itk::Image<float, 4>>::New();
			abs->SetInput(VecTo4D->GetOutput());
			writer->SetInput(abs->GetOutput());
			writer->SetFileName(filenames[i]);
			writer->Update();
		}
	}
	if (verbose) cout << "Finished all sequences." << endl;
	} catch (exception &e) {
		cerr << e.what() << endl;
		return EXIT_FAILURE;
	}
	return EXIT_SUCCESS;
}

<|endoftext|>