<commit_before>#include "editor.hh"

#include "exception.hh"
#include "utils.hh"
#include "register.hh"
#include "register_manager.hh"

#include "utf8_iterator.hh"

#include <array>

namespace Kakoune
{

Editor::Editor(Buffer& buffer)
    : m_buffer(&buffer),
      m_edition_level(0),
      m_selections(buffer)
{
    m_selections.push_back(Selection(buffer.begin(), buffer.begin()));
}

void Editor::erase()
{
    scoped_edition edition(*this);
    for (auto& sel : m_selections)
    {
        m_buffer->erase(sel.begin(), sel.end());
        sel.avoid_eol();
    }
}

static BufferIterator prepare_insert(Buffer& buffer, const Selection& sel,
                                     InsertMode mode)
{
    switch (mode)
    {
    case InsertMode::Insert:
    case InsertMode::Replace:
        return sel.begin();
    case InsertMode::Append:
    {
        // special case for end of lines, append to current line instead
        auto pos = std::max(sel.first(), sel.last());
        if (pos.column() == buffer.line_length(pos.line()) - 1)
            return pos;
        else
            return pos+1;
    }
    case InsertMode::InsertAtLineBegin:
        return buffer.iterator_at_line_begin(sel.begin());
    case InsertMode::AppendAtLineEnd:
        return buffer.iterator_at_line_end(sel.end()-1)-1;
    case InsertMode::InsertAtNextLineBegin:
        return buffer.iterator_at_line_end(sel.end()-1);
    case InsertMode::OpenLineBelow:
    {
        LineCount line = (sel.end() - 1).line();
        buffer.insert(buffer.iterator_at_line_end(line), "\n");
        return buffer.iterator_at_line_begin(line + 1);
    }
    case InsertMode::OpenLineAbove:
    {
        auto pos = buffer.iterator_at_line_begin(sel.begin());
        buffer.insert(pos, "\n");
        return pos;
    }
    }
    assert(false);
    return BufferIterator{};
}

void Editor::insert(const String& string, InsertMode mode)
{
    scoped_edition edition(*this);
    if (mode == InsertMode::Replace)
    {
        // do not call Editor::erase as we do not want to avoid end of lines
        for (auto& sel : m_selections)
            m_buffer->erase(sel.begin(), sel.end());
    }

    for (auto& sel : m_selections)
    {
        BufferIterator pos = prepare_insert(*m_buffer, sel, mode);
        m_buffer->insert(pos, string);
        sel.avoid_eol();
    }
}

void Editor::insert(const memoryview<String>& strings, InsertMode mode)
{
    scoped_edition edition(*this);
    if (mode == InsertMode::Replace)
    {
        // do not call Editor::erase as we do not want to avoid end of lines
        for (auto& sel : m_selections)
            m_buffer->erase(sel.begin(), sel.end());
    }
    if (strings.empty())
        return;

    for (size_t i = 0; i < selections().size(); ++i)
    {
        auto& sel = m_selections[i];
        BufferIterator pos = prepare_insert(*m_buffer, sel, mode);
        size_t index = std::min(i, strings.size()-1);
        m_buffer->insert(pos, strings[index]);
        sel.avoid_eol();
    }
}

std::vector<String> Editor::selections_content() const
{
    std::vector<String> contents;
    for (auto& sel : m_selections)
        contents.push_back(m_buffer->string(sel.begin(),
                                           sel.end()));
    return contents;
}

static void merge_overlapping(SelectionList& selections)
{
    for (size_t i = 0; i < selections.size(); ++i)
    {
        for (size_t j = i+1; j < selections.size();)
        {
            if (overlaps(selections[i], selections[j]))
            {
                selections[i].merge_with(selections[j]);
                selections.erase(selections.begin() + j);
            }
            else
               ++j;
        }
    }
}

void Editor::move_selections(CharCount offset, SelectMode mode)
{
    assert(mode == SelectMode::Replace or mode == SelectMode::Extend);
    for (auto& sel : m_selections)
    {
        auto last = sel.last();
        auto limit = offset < 0 ? buffer().iterator_at_line_begin(last)
                                : utf8::previous(buffer().iterator_at_line_end(last));
        last = utf8::advance(last, limit, offset);
        sel = Selection(mode == SelectMode::Extend ? sel.first() : last, last);
        sel.avoid_eol();
    }
    merge_overlapping(m_selections);
}

void Editor::move_selections(LineCount offset, SelectMode mode)
{
    assert(mode == SelectMode::Replace or mode == SelectMode::Extend);
    for (auto& sel : m_selections)
    {
        BufferCoord pos = sel.last().coord();
        pos.line += offset;
        BufferIterator last = utf8::finish(m_buffer->iterator_at(pos, true));
        sel = Selection(mode == SelectMode::Extend ? sel.first() : last, last);
        sel.avoid_eol();
    }
    merge_overlapping(m_selections);
}

void Editor::clear_selections()
{
    check_invariant();
    BufferIterator pos = m_selections.back().last();

    if (*pos == '\n' and not pos.is_begin() and *utf8::previous(pos) != '\n')
        pos = utf8::previous(pos);

    Selection sel = Selection(pos, pos);
    m_selections = SelectionList{ std::move(sel) };
}

void Editor::flip_selections()
{
    check_invariant();
    for (auto& sel : m_selections)
        std::swap(sel.first(), sel.last());
}

void Editor::keep_selection(int index)
{
    check_invariant();

    if (index < m_selections.size())
        m_selections = SelectionList{ std::move(m_selections[index]) };
}

void Editor::remove_selection(int index)
{
    check_invariant();

    if (m_selections.size() > 1 and index < m_selections.size())
        m_selections.erase(m_selections.begin() + index);
}

void Editor::select(const BufferIterator& iterator)
{
    m_selections = SelectionList{ {iterator, iterator} };
}

void Editor::select(SelectionList selections)
{
    if (selections.empty())
        throw runtime_error("no selections");
    m_selections = std::move(selections);
}

void Editor::select(const Selector& selector, SelectMode mode)
{
    check_invariant();

    if (mode == SelectMode::Append)
    {
        auto& sel = m_selections.back();
        Selection res = selector(sel);
        if (res.captures().empty())
            res.captures() = sel.captures();
        m_selections.push_back(res);
    }
    else
    {
        for (auto& sel : m_selections)
        {
            Selection res = selector(sel);
            if (mode == SelectMode::Extend)
                sel.merge_with(res);
            else
                sel = std::move(res);

            if (not res.captures().empty())
                sel.captures() = std::move(res.captures());
        }
    }
    merge_overlapping(m_selections);
}

struct nothing_selected : public runtime_error
{
    nothing_selected() : runtime_error("nothing was selected") {}
};

void Editor::multi_select(const MultiSelector& selector)
{
    check_invariant();

    SelectionList new_selections;
    for (auto& sel : m_selections)
    {
        SelectionList res = selector(sel);
        for (auto& new_sel : res)
        {
            // preserve captures when selectors captures nothing.
            if (new_sel.captures().empty())
                new_selections.emplace_back(new_sel.first(), new_sel.last(),
                                            sel.captures());
            else
                new_selections.push_back(std::move(new_sel));
        }
    }
    if (new_selections.empty())
        throw nothing_selected();
    merge_overlapping(new_selections);
    m_selections = std::move(new_selections);
}

class LastModifiedRangeListener : public BufferChangeListener
{
public:
    LastModifiedRangeListener(Buffer& buffer)
       : m_buffer(buffer)
    { m_buffer.add_change_listener(*this); }

    ~LastModifiedRangeListener()
    { m_buffer.remove_change_listener(*this); }

    void on_insert(const BufferIterator& begin, const BufferIterator& end)
    {
        m_first = begin;
        m_last = utf8::previous(end);
    }

    void on_erase(const BufferIterator& begin, const BufferIterator& end)
    {
        m_first = begin;
        if (m_first >= m_buffer.end())
            m_first = utf8::previous(m_buffer.end());
        m_last = m_first;
    }

    const BufferIterator& first() const { return m_first; }
    const BufferIterator& last() const { return m_last; }

private:
    BufferIterator m_first;
    BufferIterator m_last;
    Buffer& m_buffer;
};

bool Editor::undo()
{
    LastModifiedRangeListener listener(buffer());
    bool res = m_buffer->undo();
    if (res)
        m_selections = SelectionList{ {listener.first(), listener.last()} };
    return res;
}

bool Editor::redo()
{
    LastModifiedRangeListener listener(buffer());
    bool res = m_buffer->redo();
    if (res)
        m_selections = SelectionList{ {listener.first(), listener.last()} };
    return res;
}

void Editor::check_invariant() const
{
    assert(not m_selections.empty());
    m_selections.check_invariant();
}

void Editor::begin_edition()
{
    ++m_edition_level;

    if (m_edition_level == 1)
        m_buffer->begin_undo_group();
}

void Editor::end_edition()
{
    assert(m_edition_level > 0);
    if (m_edition_level == 1)
        m_buffer->end_undo_group();

    --m_edition_level;
}

using utf8_it = utf8::utf8_iterator<BufferIterator, utf8::InvalidBytePolicy::Pass>;

IncrementalInserter::IncrementalInserter(Editor& editor, InsertMode mode)
    : m_editor(editor), m_edition(editor), m_mode(mode)
{
    m_editor.on_incremental_insertion_begin();
    Buffer& buffer = *editor.m_buffer;

    if (mode == InsertMode::Replace)
    {
        for (auto& sel : editor.m_selections)
            buffer.erase(sel.begin(), sel.end());
    }

    for (auto& sel : m_editor.m_selections)
    {
        utf8_it first, last;
        switch (mode)
        {
        case InsertMode::Insert:  first = utf8_it(sel.end()) - 1; last = sel.begin(); break;
        case InsertMode::Replace: first = utf8_it(sel.end()) - 1; last = sel.begin(); break;
        case InsertMode::Append:  first = sel.begin(); last = sel.end(); break;

        case InsertMode::OpenLineBelow:
        case InsertMode::AppendAtLineEnd:
            first = utf8_it(buffer.iterator_at_line_end(utf8::previous(sel.end()))) - 1;
            last  = first;
            break;

        case InsertMode::OpenLineAbove:
        case InsertMode::InsertAtLineBegin:
            first = buffer.iterator_at_line_begin(sel.begin());
            if (mode == InsertMode::OpenLineAbove)
                --first;
            else
            {
                auto first_non_blank = first;
                while (*first_non_blank == ' ' or *first_non_blank == '\t')
                    ++first_non_blank;
                if (*first_non_blank != '\n')
                    first = first_non_blank;
            }
            last = first;
            break;
        }
        if (first.underlying_iterator().is_end())
           --first;
        if (last.underlying_iterator().is_end())
           --last;
        sel = Selection(first.underlying_iterator(), last.underlying_iterator());
    }
    if (mode == InsertMode::OpenLineBelow or mode == InsertMode::OpenLineAbove)
    {
        insert("\n");
        if (mode == InsertMode::OpenLineAbove)
        {
            for (auto& sel : m_editor.m_selections)
            {
                // special case, the --first line above did nothing, so we need to compensate now
                if (sel.first() == utf8::next(buffer.begin()))
                    sel = Selection(buffer.begin(), buffer.begin());
            }
        }
    }
}

IncrementalInserter::~IncrementalInserter()
{
    for (auto& sel : m_editor.m_selections)
    {
        if (m_mode == InsertMode::Append)
            sel = Selection(sel.first(), utf8::previous(sel.last()));
         sel.avoid_eol();
    }

    m_editor.on_incremental_insertion_end();
}

void IncrementalInserter::insert(String content)
{
    Buffer& buffer = m_editor.buffer();
    for (auto& sel : m_editor.m_selections)
    {
        m_editor.filters()(buffer, sel, content);
        buffer.insert(sel.last(), content);
    }
}

void IncrementalInserter::insert(const memoryview<String>& strings)
{
    for (size_t i = 0; i < m_editor.m_selections.size(); ++i)
    {
        size_t index = std::min(i, strings.size()-1);
        m_editor.buffer().insert(m_editor.m_selections[i].last(),
                                 strings[index]);
    }
}

void IncrementalInserter::erase()
{
    for (auto& sel : m_editor.m_selections)
    {
        BufferIterator pos = sel.last();
        m_editor.buffer().erase(utf8::previous(pos), pos);
    }
}

void IncrementalInserter::move_cursors(CharCount move)
{
    m_editor.move_selections(move, SelectMode::Replace);
}

void IncrementalInserter::move_cursors(LineCount move)
{
    m_editor.move_selections(move, SelectMode::Replace);
}

}
<commit_msg>optimize merge_overlappings<commit_after>#include "editor.hh"

#include "exception.hh"
#include "utils.hh"
#include "register.hh"
#include "register_manager.hh"

#include "utf8_iterator.hh"

#include <array>

namespace Kakoune
{

Editor::Editor(Buffer& buffer)
    : m_buffer(&buffer),
      m_edition_level(0),
      m_selections(buffer)
{
    m_selections.push_back(Selection(buffer.begin(), buffer.begin()));
}

void Editor::erase()
{
    scoped_edition edition(*this);
    for (auto& sel : m_selections)
    {
        m_buffer->erase(sel.begin(), sel.end());
        sel.avoid_eol();
    }
}

static BufferIterator prepare_insert(Buffer& buffer, const Selection& sel,
                                     InsertMode mode)
{
    switch (mode)
    {
    case InsertMode::Insert:
    case InsertMode::Replace:
        return sel.begin();
    case InsertMode::Append:
    {
        // special case for end of lines, append to current line instead
        auto pos = std::max(sel.first(), sel.last());
        if (pos.column() == buffer.line_length(pos.line()) - 1)
            return pos;
        else
            return pos+1;
    }
    case InsertMode::InsertAtLineBegin:
        return buffer.iterator_at_line_begin(sel.begin());
    case InsertMode::AppendAtLineEnd:
        return buffer.iterator_at_line_end(sel.end()-1)-1;
    case InsertMode::InsertAtNextLineBegin:
        return buffer.iterator_at_line_end(sel.end()-1);
    case InsertMode::OpenLineBelow:
    {
        LineCount line = (sel.end() - 1).line();
        buffer.insert(buffer.iterator_at_line_end(line), "\n");
        return buffer.iterator_at_line_begin(line + 1);
    }
    case InsertMode::OpenLineAbove:
    {
        auto pos = buffer.iterator_at_line_begin(sel.begin());
        buffer.insert(pos, "\n");
        return pos;
    }
    }
    assert(false);
    return BufferIterator{};
}

void Editor::insert(const String& string, InsertMode mode)
{
    scoped_edition edition(*this);
    if (mode == InsertMode::Replace)
    {
        // do not call Editor::erase as we do not want to avoid end of lines
        for (auto& sel : m_selections)
            m_buffer->erase(sel.begin(), sel.end());
    }

    for (auto& sel : m_selections)
    {
        BufferIterator pos = prepare_insert(*m_buffer, sel, mode);
        m_buffer->insert(pos, string);
        sel.avoid_eol();
    }
}

void Editor::insert(const memoryview<String>& strings, InsertMode mode)
{
    scoped_edition edition(*this);
    if (mode == InsertMode::Replace)
    {
        // do not call Editor::erase as we do not want to avoid end of lines
        for (auto& sel : m_selections)
            m_buffer->erase(sel.begin(), sel.end());
    }
    if (strings.empty())
        return;

    for (size_t i = 0; i < selections().size(); ++i)
    {
        auto& sel = m_selections[i];
        BufferIterator pos = prepare_insert(*m_buffer, sel, mode);
        size_t index = std::min(i, strings.size()-1);
        m_buffer->insert(pos, strings[index]);
        sel.avoid_eol();
    }
}

std::vector<String> Editor::selections_content() const
{
    std::vector<String> contents;
    for (auto& sel : m_selections)
        contents.push_back(m_buffer->string(sel.begin(),
                                           sel.end()));
    return contents;
}

static void merge_overlapping(SelectionList& selections)
{
    assert(std::is_sorted(selections.begin(), selections.end(),
                          [](const Selection& lhs, const Selection& rhs)
                          { return lhs.begin() < rhs.begin(); }));
    for (size_t i = 0; i < selections.size()-1;)
    {
        if (overlaps(selections[i], selections[i+1]))
        {
            selections[i].merge_with(selections[i+1]);
            selections.erase(selections.begin() + i + 1);
        }
        else
           ++i;
    }
}

void Editor::move_selections(CharCount offset, SelectMode mode)
{
    assert(mode == SelectMode::Replace or mode == SelectMode::Extend);
    for (auto& sel : m_selections)
    {
        auto last = sel.last();
        auto limit = offset < 0 ? buffer().iterator_at_line_begin(last)
                                : utf8::previous(buffer().iterator_at_line_end(last));
        last = utf8::advance(last, limit, offset);
        sel = Selection(mode == SelectMode::Extend ? sel.first() : last, last);
        sel.avoid_eol();
    }
    merge_overlapping(m_selections);
}

void Editor::move_selections(LineCount offset, SelectMode mode)
{
    assert(mode == SelectMode::Replace or mode == SelectMode::Extend);
    for (auto& sel : m_selections)
    {
        BufferCoord pos = sel.last().coord();
        pos.line += offset;
        BufferIterator last = utf8::finish(m_buffer->iterator_at(pos, true));
        sel = Selection(mode == SelectMode::Extend ? sel.first() : last, last);
        sel.avoid_eol();
    }
    merge_overlapping(m_selections);
}

void Editor::clear_selections()
{
    check_invariant();
    BufferIterator pos = m_selections.back().last();

    if (*pos == '\n' and not pos.is_begin() and *utf8::previous(pos) != '\n')
        pos = utf8::previous(pos);

    Selection sel = Selection(pos, pos);
    m_selections = SelectionList{ std::move(sel) };
}

void Editor::flip_selections()
{
    check_invariant();
    for (auto& sel : m_selections)
        std::swap(sel.first(), sel.last());
}

void Editor::keep_selection(int index)
{
    check_invariant();

    if (index < m_selections.size())
        m_selections = SelectionList{ std::move(m_selections[index]) };
}

void Editor::remove_selection(int index)
{
    check_invariant();

    if (m_selections.size() > 1 and index < m_selections.size())
        m_selections.erase(m_selections.begin() + index);
}

void Editor::select(const BufferIterator& iterator)
{
    m_selections = SelectionList{ {iterator, iterator} };
}

void Editor::select(SelectionList selections)
{
    if (selections.empty())
        throw runtime_error("no selections");
    m_selections = std::move(selections);
}

void Editor::select(const Selector& selector, SelectMode mode)
{
    check_invariant();

    if (mode == SelectMode::Append)
    {
        auto& sel = m_selections.back();
        Selection res = selector(sel);
        if (res.captures().empty())
            res.captures() = sel.captures();
        m_selections.push_back(res);
    }
    else
    {
        for (auto& sel : m_selections)
        {
            Selection res = selector(sel);
            if (mode == SelectMode::Extend)
                sel.merge_with(res);
            else
                sel = std::move(res);

            if (not res.captures().empty())
                sel.captures() = std::move(res.captures());
        }
    }
    merge_overlapping(m_selections);
}

struct nothing_selected : public runtime_error
{
    nothing_selected() : runtime_error("nothing was selected") {}
};

void Editor::multi_select(const MultiSelector& selector)
{
    check_invariant();

    SelectionList new_selections;
    for (auto& sel : m_selections)
    {
        SelectionList res = selector(sel);
        for (auto& new_sel : res)
        {
            // preserve captures when selectors captures nothing.
            if (new_sel.captures().empty())
                new_selections.emplace_back(new_sel.first(), new_sel.last(),
                                            sel.captures());
            else
                new_selections.push_back(std::move(new_sel));
        }
    }
    if (new_selections.empty())
        throw nothing_selected();
    merge_overlapping(new_selections);
    m_selections = std::move(new_selections);
}

class LastModifiedRangeListener : public BufferChangeListener
{
public:
    LastModifiedRangeListener(Buffer& buffer)
       : m_buffer(buffer)
    { m_buffer.add_change_listener(*this); }

    ~LastModifiedRangeListener()
    { m_buffer.remove_change_listener(*this); }

    void on_insert(const BufferIterator& begin, const BufferIterator& end)
    {
        m_first = begin;
        m_last = utf8::previous(end);
    }

    void on_erase(const BufferIterator& begin, const BufferIterator& end)
    {
        m_first = begin;
        if (m_first >= m_buffer.end())
            m_first = utf8::previous(m_buffer.end());
        m_last = m_first;
    }

    const BufferIterator& first() const { return m_first; }
    const BufferIterator& last() const { return m_last; }

private:
    BufferIterator m_first;
    BufferIterator m_last;
    Buffer& m_buffer;
};

bool Editor::undo()
{
    LastModifiedRangeListener listener(buffer());
    bool res = m_buffer->undo();
    if (res)
        m_selections = SelectionList{ {listener.first(), listener.last()} };
    return res;
}

bool Editor::redo()
{
    LastModifiedRangeListener listener(buffer());
    bool res = m_buffer->redo();
    if (res)
        m_selections = SelectionList{ {listener.first(), listener.last()} };
    return res;
}

void Editor::check_invariant() const
{
    assert(not m_selections.empty());
    m_selections.check_invariant();
}

void Editor::begin_edition()
{
    ++m_edition_level;

    if (m_edition_level == 1)
        m_buffer->begin_undo_group();
}

void Editor::end_edition()
{
    assert(m_edition_level > 0);
    if (m_edition_level == 1)
        m_buffer->end_undo_group();

    --m_edition_level;
}

using utf8_it = utf8::utf8_iterator<BufferIterator, utf8::InvalidBytePolicy::Pass>;

IncrementalInserter::IncrementalInserter(Editor& editor, InsertMode mode)
    : m_editor(editor), m_edition(editor), m_mode(mode)
{
    m_editor.on_incremental_insertion_begin();
    Buffer& buffer = *editor.m_buffer;

    if (mode == InsertMode::Replace)
    {
        for (auto& sel : editor.m_selections)
            buffer.erase(sel.begin(), sel.end());
    }

    for (auto& sel : m_editor.m_selections)
    {
        utf8_it first, last;
        switch (mode)
        {
        case InsertMode::Insert:  first = utf8_it(sel.end()) - 1; last = sel.begin(); break;
        case InsertMode::Replace: first = utf8_it(sel.end()) - 1; last = sel.begin(); break;
        case InsertMode::Append:  first = sel.begin(); last = sel.end(); break;

        case InsertMode::OpenLineBelow:
        case InsertMode::AppendAtLineEnd:
            first = utf8_it(buffer.iterator_at_line_end(utf8::previous(sel.end()))) - 1;
            last  = first;
            break;

        case InsertMode::OpenLineAbove:
        case InsertMode::InsertAtLineBegin:
            first = buffer.iterator_at_line_begin(sel.begin());
            if (mode == InsertMode::OpenLineAbove)
                --first;
            else
            {
                auto first_non_blank = first;
                while (*first_non_blank == ' ' or *first_non_blank == '\t')
                    ++first_non_blank;
                if (*first_non_blank != '\n')
                    first = first_non_blank;
            }
            last = first;
            break;
        }
        if (first.underlying_iterator().is_end())
           --first;
        if (last.underlying_iterator().is_end())
           --last;
        sel = Selection(first.underlying_iterator(), last.underlying_iterator());
    }
    if (mode == InsertMode::OpenLineBelow or mode == InsertMode::OpenLineAbove)
    {
        insert("\n");
        if (mode == InsertMode::OpenLineAbove)
        {
            for (auto& sel : m_editor.m_selections)
            {
                // special case, the --first line above did nothing, so we need to compensate now
                if (sel.first() == utf8::next(buffer.begin()))
                    sel = Selection(buffer.begin(), buffer.begin());
            }
        }
    }
}

IncrementalInserter::~IncrementalInserter()
{
    for (auto& sel : m_editor.m_selections)
    {
        if (m_mode == InsertMode::Append)
            sel = Selection(sel.first(), utf8::previous(sel.last()));
         sel.avoid_eol();
    }

    m_editor.on_incremental_insertion_end();
}

void IncrementalInserter::insert(String content)
{
    Buffer& buffer = m_editor.buffer();
    for (auto& sel : m_editor.m_selections)
    {
        m_editor.filters()(buffer, sel, content);
        buffer.insert(sel.last(), content);
    }
}

void IncrementalInserter::insert(const memoryview<String>& strings)
{
    for (size_t i = 0; i < m_editor.m_selections.size(); ++i)
    {
        size_t index = std::min(i, strings.size()-1);
        m_editor.buffer().insert(m_editor.m_selections[i].last(),
                                 strings[index]);
    }
}

void IncrementalInserter::erase()
{
    for (auto& sel : m_editor.m_selections)
    {
        BufferIterator pos = sel.last();
        m_editor.buffer().erase(utf8::previous(pos), pos);
    }
}

void IncrementalInserter::move_cursors(CharCount move)
{
    m_editor.move_selections(move, SelectMode::Replace);
}

void IncrementalInserter::move_cursors(LineCount move)
{
    m_editor.move_selections(move, SelectMode::Replace);
}

}
<|endoftext|>


<commit_before>#include "editor.hh"

#include "exception.hh"
#include "utils.hh"
#include "register.hh"
#include "register_manager.hh"

#include "utf8_iterator.hh"

#include <array>

namespace Kakoune
{

Editor::Editor(Buffer& buffer)
    : m_buffer(&buffer),
      m_edition_level(0)
{
    m_selections.push_back(Selection(buffer.begin(), buffer.begin()));
}

void Editor::erase()
{
    scoped_edition edition(*this);
    for (auto& sel : m_selections)
    {
        m_buffer->erase(sel.begin(), sel.end());
        sel.selection.avoid_eol();
    }
}

static BufferIterator prepare_insert(Buffer& buffer, const Selection& sel,
                                     InsertMode mode)
{
    switch (mode)
    {
    case InsertMode::Insert:
    case InsertMode::Replace:
        return sel.begin();
    case InsertMode::Append:
        return sel.end();
    case InsertMode::InsertAtLineBegin:
        return buffer.iterator_at_line_begin(sel.begin());
    case InsertMode::AppendAtLineEnd:
        return buffer.iterator_at_line_end(sel.end()-1);
    case InsertMode::OpenLineBelow:
    {
        auto pos = buffer.iterator_at_line_end(sel.end() - 1);
        buffer.insert(pos, "\n");
        return buffer.iterator_at_line_begin(pos.line() + 1);
    }
    case InsertMode::OpenLineAbove:
    {
        auto pos = buffer.iterator_at_line_begin(sel.begin());
        buffer.insert(pos, "\n");
        return pos;
    }
    }
    assert(false);
    return BufferIterator{};
}

void Editor::insert(const String& string, InsertMode mode)
{
    scoped_edition edition(*this);
    if (mode == InsertMode::Replace)
        erase();

    for (auto& sel : m_selections)
    {
        BufferIterator pos = prepare_insert(*m_buffer, sel.selection, mode);
        m_buffer->insert(pos, string);
    }
}

void Editor::insert(const memoryview<String>& strings, InsertMode mode)
{
    scoped_edition edition(*this);
    if (mode == InsertMode::Replace)
        erase();

    if (strings.empty())
        return;

    for (size_t i = 0; i < selections().size(); ++i)
    {
        BufferIterator pos = prepare_insert(*m_buffer, m_selections[i].selection, mode);
        size_t index = std::min(i, strings.size()-1);
        m_buffer->insert(pos, strings[index]);
    }
}

std::vector<String> Editor::selections_content() const
{
    std::vector<String> contents;
    for (auto& sel : m_selections)
        contents.push_back(m_buffer->string(sel.begin(),
                                           sel.end()));
    return contents;
}

static bool overlaps(const SelectionAndCaptures& lhs,
                     const SelectionAndCaptures& rhs)
{
    return (lhs.first() <= rhs.first() and lhs.last() >= rhs.first()) or
           (lhs.first() <= rhs.last()  and lhs.last() >= rhs.last());
}

static void merge_overlapping(SelectionAndCapturesList& selections)
{
    for (size_t i = 0; i < selections.size(); ++i)
    {
        for (size_t j = i+1; j < selections.size();)
        {
            if (overlaps(selections[i], selections[j]))
            {
                selections[i].selection.merge_with(selections[j].selection);
                selections.erase(selections.begin() + j);
            }
            else
               ++j;
        }
    }
}

void Editor::move_selections(CharCount offset, SelectMode mode)
{
    assert(mode == SelectMode::Replace or mode == SelectMode::Extend);
    for (auto& sel : m_selections)
    {
        auto last = sel.last();
        auto limit = offset < 0 ? buffer().iterator_at_line_begin(last)
                                : utf8::previous(buffer().iterator_at_line_end(last));
        last = utf8::advance(last, limit, offset);
        sel.selection = Selection(mode == SelectMode::Extend ? sel.first() : last, last);
    }
    merge_overlapping(m_selections);
}

void Editor::move_selections(LineCount offset, SelectMode mode)
{
    assert(mode == SelectMode::Replace or mode == SelectMode::Extend);
    for (auto& sel : m_selections)
    {
        BufferCoord pos = m_buffer->line_and_column_at(sel.last());
        pos.line += offset;
        BufferIterator last = utf8::finish(m_buffer->iterator_at(pos, true));
        sel.selection = Selection(mode == SelectMode::Extend ? sel.first() : last, last);
    }
    merge_overlapping(m_selections);
}

void Editor::clear_selections()
{
    check_invariant();
    BufferIterator pos = m_selections.back().last();

    if (*pos == '\n' and not pos.is_begin() and *utf8::previous(pos) != '\n')
        pos = utf8::previous(pos);

    Selection sel = Selection(pos, pos);
    m_selections.clear();
    m_selections.push_back(std::move(sel));
}

void Editor::keep_selection(int index)
{
    check_invariant();

    if (index < m_selections.size())
    {
        SelectionAndCaptures sel = std::move(m_selections[index]);
        m_selections.clear();
        m_selections.push_back(std::move(sel));
    }
}

void Editor::remove_selection(int index)
{
    check_invariant();

    if (m_selections.size() > 1 and index < m_selections.size())
        m_selections.erase(m_selections.begin() + index);
}

void Editor::select(const BufferIterator& iterator)
{
    m_selections.clear();
    m_selections.push_back(Selection(iterator, iterator));
}

void Editor::select(SelectionAndCapturesList selections)
{
    if (selections.empty())
        throw runtime_error("no selections");
    m_selections = std::move(selections);
}

void Editor::select(const Selector& selector, SelectMode mode)
{
    check_invariant();

    if (mode == SelectMode::Append)
    {
        auto& sel = m_selections.back();
        SelectionAndCaptures res = selector(sel.selection);
        if (res.captures.empty())
            res.captures = sel.captures;
        m_selections.push_back(res);
    }
    else
    {
        for (auto& sel : m_selections)
        {
            SelectionAndCaptures res = selector(sel.selection);
            if (mode == SelectMode::Extend)
                sel.selection.merge_with(res.selection);
            else
                sel.selection = std::move(res.selection);

            if (not res.captures.empty())
                sel.captures = std::move(res.captures);
        }
    }
    merge_overlapping(m_selections);
}

struct nothing_selected : public runtime_error
{
    nothing_selected() : runtime_error("nothing was selected") {}
};

void Editor::multi_select(const MultiSelector& selector)
{
    check_invariant();

    SelectionAndCapturesList new_selections;
    for (auto& sel : m_selections)
    {
        SelectionAndCapturesList res = selector(sel.selection);
        for (auto& sel_and_cap : res)
        {
            // preserve captures when selectors captures nothing.
            if (sel_and_cap.captures.empty())
                new_selections.emplace_back(sel_and_cap.selection, sel.captures);
            else
                new_selections.push_back(std::move(sel_and_cap));
        }
    }
    if (new_selections.empty())
        throw nothing_selected();

    merge_overlapping(new_selections);
    m_selections = std::move(new_selections);
}

class LastModifiedRangeListener : public BufferChangeListener
{
public:
    LastModifiedRangeListener(Buffer& buffer)
       : m_buffer(buffer)
    { m_buffer.add_change_listener(*this); }

    ~LastModifiedRangeListener()
    { m_buffer.remove_change_listener(*this); }

    void on_insert(const BufferIterator& begin, const BufferIterator& end)
    {
        m_first = begin;
        m_last = utf8::previous(end);
    }

    void on_erase(const BufferIterator& begin, const BufferIterator& end)
    {
        m_first = begin;
        if (m_first >= m_buffer.end())
            m_first = utf8::previous(m_buffer.end());
        m_last = m_first;
    }

    const BufferIterator& first() const { return m_first; }
    const BufferIterator& last() const { return m_last; }

private:
    BufferIterator m_first;
    BufferIterator m_last;
    Buffer& m_buffer;
};

bool Editor::undo()
{
    LastModifiedRangeListener listener(buffer());
    bool res = m_buffer->undo();
    if (res)
    {
        m_selections.clear();
        m_selections.push_back(Selection(listener.first(),
                                         listener.last()));
    }
    return res;
}

bool Editor::redo()
{
    LastModifiedRangeListener listener(buffer());
    bool res = m_buffer->redo();
    if (res)
    {
        m_selections.clear();
        m_selections.push_back(Selection(listener.first(),
                                         listener.last()));
    }
    return res;
}

void Editor::check_invariant() const
{
    assert(not m_selections.empty());
}

void Editor::begin_edition()
{
    ++m_edition_level;

    if (m_edition_level == 1)
        m_buffer->begin_undo_group();
}

void Editor::end_edition()
{
    assert(m_edition_level > 0);
    if (m_edition_level == 1)
        m_buffer->end_undo_group();

    --m_edition_level;
}

using utf8_it = utf8::utf8_iterator<BufferIterator, utf8::InvalidBytePolicy::Pass>;

IncrementalInserter::IncrementalInserter(Editor& editor, InsertMode mode)
    : m_editor(editor), m_edition(editor), m_mode(mode)
{
    m_editor.on_incremental_insertion_begin();
    Buffer& buffer = *editor.m_buffer;

    if (mode == InsertMode::Replace)
    {
        for (auto& sel : editor.m_selections)
            buffer.erase(sel.begin(), sel.end());
    }

    for (auto& sel : m_editor.m_selections)
    {
        utf8_it first, last;
        switch (mode)
        {
        case InsertMode::Insert:  first = utf8_it(sel.end()) - 1; last = sel.begin(); break;
        case InsertMode::Replace: first = utf8_it(sel.end()) - 1; last = sel.begin(); break;
        case InsertMode::Append:  first = sel.begin(); last = sel.end(); break;

        case InsertMode::OpenLineBelow:
        case InsertMode::AppendAtLineEnd:
            first = utf8_it(buffer.iterator_at_line_end(utf8::previous(sel.end()))) - 1;
            last  = first;
            break;

        case InsertMode::OpenLineAbove:
        case InsertMode::InsertAtLineBegin:
            first = buffer.iterator_at_line_begin(sel.begin());
            if (mode == InsertMode::OpenLineAbove)
                --first;
            else
            {
                auto first_non_blank = first;
                while (*first_non_blank == ' ' or *first_non_blank == '\t')
                    ++first_non_blank;
                if (*first_non_blank != '\n')
                    first = first_non_blank;
            }
            last = first;
            break;
        }
        if (first.underlying_iterator().is_end())
           --first;
        if (last.underlying_iterator().is_end())
           --last;
        sel.selection = Selection(first.underlying_iterator(), last.underlying_iterator());
    }
    if (mode == InsertMode::OpenLineBelow or mode == InsertMode::OpenLineAbove)
    {
        insert("\n");
        if (mode == InsertMode::OpenLineAbove)
        {
            for (auto& sel : m_editor.m_selections)
            {
                // special case, the --first line above did nothing, so we need to compensate now
                if (sel.first() == utf8::next(buffer.begin()))
                    sel.selection = Selection(buffer.begin(), buffer.begin());
            }
        }
    }
}

IncrementalInserter::~IncrementalInserter()
{
    for (auto& sel : m_editor.m_selections)
    {
        if (m_mode == InsertMode::Append)
            sel = Selection(sel.first(), utf8::previous(sel.last()));
         sel.selection.avoid_eol();
    }

    m_editor.on_incremental_insertion_end();
}

void IncrementalInserter::insert(const String& string)
{
    Buffer& buffer = m_editor.buffer();
    for (auto& sel : m_editor.m_selections)
    {
        BufferIterator position = sel.last();
        String content = string;
        m_editor.filters()(buffer, position, content);
        m_editor.buffer().insert(position, content);
    }
}

void IncrementalInserter::insert(const memoryview<String>& strings)
{
    m_editor.insert(strings);
}

void IncrementalInserter::erase()
{
    for (auto& sel : m_editor.m_selections)
    {
        BufferIterator pos = sel.last();
        m_editor.buffer().erase(utf8::previous(pos), pos);
    }
}

void IncrementalInserter::move_cursors(const BufferCoord& offset)
{
    for (auto& sel : m_editor.m_selections)
    {
        BufferCoord pos = m_editor.m_buffer->line_and_column_at(sel.last());
        BufferIterator it = m_editor.m_buffer->iterator_at(pos + offset);
        sel = Selection(it, it);
    }
}

}
<commit_msg>Editor: avoid end of lines when moving selection<commit_after>#include "editor.hh"

#include "exception.hh"
#include "utils.hh"
#include "register.hh"
#include "register_manager.hh"

#include "utf8_iterator.hh"

#include <array>

namespace Kakoune
{

Editor::Editor(Buffer& buffer)
    : m_buffer(&buffer),
      m_edition_level(0)
{
    m_selections.push_back(Selection(buffer.begin(), buffer.begin()));
}

void Editor::erase()
{
    scoped_edition edition(*this);
    for (auto& sel : m_selections)
    {
        m_buffer->erase(sel.begin(), sel.end());
        sel.selection.avoid_eol();
    }
}

static BufferIterator prepare_insert(Buffer& buffer, const Selection& sel,
                                     InsertMode mode)
{
    switch (mode)
    {
    case InsertMode::Insert:
    case InsertMode::Replace:
        return sel.begin();
    case InsertMode::Append:
        return sel.end();
    case InsertMode::InsertAtLineBegin:
        return buffer.iterator_at_line_begin(sel.begin());
    case InsertMode::AppendAtLineEnd:
        return buffer.iterator_at_line_end(sel.end()-1);
    case InsertMode::OpenLineBelow:
    {
        auto pos = buffer.iterator_at_line_end(sel.end() - 1);
        buffer.insert(pos, "\n");
        return buffer.iterator_at_line_begin(pos.line() + 1);
    }
    case InsertMode::OpenLineAbove:
    {
        auto pos = buffer.iterator_at_line_begin(sel.begin());
        buffer.insert(pos, "\n");
        return pos;
    }
    }
    assert(false);
    return BufferIterator{};
}

void Editor::insert(const String& string, InsertMode mode)
{
    scoped_edition edition(*this);
    if (mode == InsertMode::Replace)
        erase();

    for (auto& sel : m_selections)
    {
        BufferIterator pos = prepare_insert(*m_buffer, sel.selection, mode);
        m_buffer->insert(pos, string);
    }
}

void Editor::insert(const memoryview<String>& strings, InsertMode mode)
{
    scoped_edition edition(*this);
    if (mode == InsertMode::Replace)
        erase();

    if (strings.empty())
        return;

    for (size_t i = 0; i < selections().size(); ++i)
    {
        BufferIterator pos = prepare_insert(*m_buffer, m_selections[i].selection, mode);
        size_t index = std::min(i, strings.size()-1);
        m_buffer->insert(pos, strings[index]);
    }
}

std::vector<String> Editor::selections_content() const
{
    std::vector<String> contents;
    for (auto& sel : m_selections)
        contents.push_back(m_buffer->string(sel.begin(),
                                           sel.end()));
    return contents;
}

static bool overlaps(const SelectionAndCaptures& lhs,
                     const SelectionAndCaptures& rhs)
{
    return (lhs.first() <= rhs.first() and lhs.last() >= rhs.first()) or
           (lhs.first() <= rhs.last()  and lhs.last() >= rhs.last());
}

static void merge_overlapping(SelectionAndCapturesList& selections)
{
    for (size_t i = 0; i < selections.size(); ++i)
    {
        for (size_t j = i+1; j < selections.size();)
        {
            if (overlaps(selections[i], selections[j]))
            {
                selections[i].selection.merge_with(selections[j].selection);
                selections.erase(selections.begin() + j);
            }
            else
               ++j;
        }
    }
}

void Editor::move_selections(CharCount offset, SelectMode mode)
{
    assert(mode == SelectMode::Replace or mode == SelectMode::Extend);
    for (auto& sel : m_selections)
    {
        auto last = sel.last();
        auto limit = offset < 0 ? buffer().iterator_at_line_begin(last)
                                : utf8::previous(buffer().iterator_at_line_end(last));
        last = utf8::advance(last, limit, offset);
        sel.selection = Selection(mode == SelectMode::Extend ? sel.first() : last, last);
        sel.selection.avoid_eol();
    }
    merge_overlapping(m_selections);
}

void Editor::move_selections(LineCount offset, SelectMode mode)
{
    assert(mode == SelectMode::Replace or mode == SelectMode::Extend);
    for (auto& sel : m_selections)
    {
        BufferCoord pos = m_buffer->line_and_column_at(sel.last());
        pos.line += offset;
        BufferIterator last = utf8::finish(m_buffer->iterator_at(pos, true));
        sel.selection = Selection(mode == SelectMode::Extend ? sel.first() : last, last);
        sel.selection.avoid_eol();
    }
    merge_overlapping(m_selections);
}

void Editor::clear_selections()
{
    check_invariant();
    BufferIterator pos = m_selections.back().last();

    if (*pos == '\n' and not pos.is_begin() and *utf8::previous(pos) != '\n')
        pos = utf8::previous(pos);

    Selection sel = Selection(pos, pos);
    m_selections.clear();
    m_selections.push_back(std::move(sel));
}

void Editor::keep_selection(int index)
{
    check_invariant();

    if (index < m_selections.size())
    {
        SelectionAndCaptures sel = std::move(m_selections[index]);
        m_selections.clear();
        m_selections.push_back(std::move(sel));
    }
}

void Editor::remove_selection(int index)
{
    check_invariant();

    if (m_selections.size() > 1 and index < m_selections.size())
        m_selections.erase(m_selections.begin() + index);
}

void Editor::select(const BufferIterator& iterator)
{
    m_selections.clear();
    m_selections.push_back(Selection(iterator, iterator));
}

void Editor::select(SelectionAndCapturesList selections)
{
    if (selections.empty())
        throw runtime_error("no selections");
    m_selections = std::move(selections);
}

void Editor::select(const Selector& selector, SelectMode mode)
{
    check_invariant();

    if (mode == SelectMode::Append)
    {
        auto& sel = m_selections.back();
        SelectionAndCaptures res = selector(sel.selection);
        if (res.captures.empty())
            res.captures = sel.captures;
        m_selections.push_back(res);
    }
    else
    {
        for (auto& sel : m_selections)
        {
            SelectionAndCaptures res = selector(sel.selection);
            if (mode == SelectMode::Extend)
                sel.selection.merge_with(res.selection);
            else
                sel.selection = std::move(res.selection);

            if (not res.captures.empty())
                sel.captures = std::move(res.captures);
        }
    }
    merge_overlapping(m_selections);
}

struct nothing_selected : public runtime_error
{
    nothing_selected() : runtime_error("nothing was selected") {}
};

void Editor::multi_select(const MultiSelector& selector)
{
    check_invariant();

    SelectionAndCapturesList new_selections;
    for (auto& sel : m_selections)
    {
        SelectionAndCapturesList res = selector(sel.selection);
        for (auto& sel_and_cap : res)
        {
            // preserve captures when selectors captures nothing.
            if (sel_and_cap.captures.empty())
                new_selections.emplace_back(sel_and_cap.selection, sel.captures);
            else
                new_selections.push_back(std::move(sel_and_cap));
        }
    }
    if (new_selections.empty())
        throw nothing_selected();

    merge_overlapping(new_selections);
    m_selections = std::move(new_selections);
}

class LastModifiedRangeListener : public BufferChangeListener
{
public:
    LastModifiedRangeListener(Buffer& buffer)
       : m_buffer(buffer)
    { m_buffer.add_change_listener(*this); }

    ~LastModifiedRangeListener()
    { m_buffer.remove_change_listener(*this); }

    void on_insert(const BufferIterator& begin, const BufferIterator& end)
    {
        m_first = begin;
        m_last = utf8::previous(end);
    }

    void on_erase(const BufferIterator& begin, const BufferIterator& end)
    {
        m_first = begin;
        if (m_first >= m_buffer.end())
            m_first = utf8::previous(m_buffer.end());
        m_last = m_first;
    }

    const BufferIterator& first() const { return m_first; }
    const BufferIterator& last() const { return m_last; }

private:
    BufferIterator m_first;
    BufferIterator m_last;
    Buffer& m_buffer;
};

bool Editor::undo()
{
    LastModifiedRangeListener listener(buffer());
    bool res = m_buffer->undo();
    if (res)
    {
        m_selections.clear();
        m_selections.push_back(Selection(listener.first(),
                                         listener.last()));
    }
    return res;
}

bool Editor::redo()
{
    LastModifiedRangeListener listener(buffer());
    bool res = m_buffer->redo();
    if (res)
    {
        m_selections.clear();
        m_selections.push_back(Selection(listener.first(),
                                         listener.last()));
    }
    return res;
}

void Editor::check_invariant() const
{
    assert(not m_selections.empty());
}

void Editor::begin_edition()
{
    ++m_edition_level;

    if (m_edition_level == 1)
        m_buffer->begin_undo_group();
}

void Editor::end_edition()
{
    assert(m_edition_level > 0);
    if (m_edition_level == 1)
        m_buffer->end_undo_group();

    --m_edition_level;
}

using utf8_it = utf8::utf8_iterator<BufferIterator, utf8::InvalidBytePolicy::Pass>;

IncrementalInserter::IncrementalInserter(Editor& editor, InsertMode mode)
    : m_editor(editor), m_edition(editor), m_mode(mode)
{
    m_editor.on_incremental_insertion_begin();
    Buffer& buffer = *editor.m_buffer;

    if (mode == InsertMode::Replace)
    {
        for (auto& sel : editor.m_selections)
            buffer.erase(sel.begin(), sel.end());
    }

    for (auto& sel : m_editor.m_selections)
    {
        utf8_it first, last;
        switch (mode)
        {
        case InsertMode::Insert:  first = utf8_it(sel.end()) - 1; last = sel.begin(); break;
        case InsertMode::Replace: first = utf8_it(sel.end()) - 1; last = sel.begin(); break;
        case InsertMode::Append:  first = sel.begin(); last = sel.end(); break;

        case InsertMode::OpenLineBelow:
        case InsertMode::AppendAtLineEnd:
            first = utf8_it(buffer.iterator_at_line_end(utf8::previous(sel.end()))) - 1;
            last  = first;
            break;

        case InsertMode::OpenLineAbove:
        case InsertMode::InsertAtLineBegin:
            first = buffer.iterator_at_line_begin(sel.begin());
            if (mode == InsertMode::OpenLineAbove)
                --first;
            else
            {
                auto first_non_blank = first;
                while (*first_non_blank == ' ' or *first_non_blank == '\t')
                    ++first_non_blank;
                if (*first_non_blank != '\n')
                    first = first_non_blank;
            }
            last = first;
            break;
        }
        if (first.underlying_iterator().is_end())
           --first;
        if (last.underlying_iterator().is_end())
           --last;
        sel.selection = Selection(first.underlying_iterator(), last.underlying_iterator());
    }
    if (mode == InsertMode::OpenLineBelow or mode == InsertMode::OpenLineAbove)
    {
        insert("\n");
        if (mode == InsertMode::OpenLineAbove)
        {
            for (auto& sel : m_editor.m_selections)
            {
                // special case, the --first line above did nothing, so we need to compensate now
                if (sel.first() == utf8::next(buffer.begin()))
                    sel.selection = Selection(buffer.begin(), buffer.begin());
            }
        }
    }
}

IncrementalInserter::~IncrementalInserter()
{
    for (auto& sel : m_editor.m_selections)
    {
        if (m_mode == InsertMode::Append)
            sel = Selection(sel.first(), utf8::previous(sel.last()));
         sel.selection.avoid_eol();
    }

    m_editor.on_incremental_insertion_end();
}

void IncrementalInserter::insert(const String& string)
{
    Buffer& buffer = m_editor.buffer();
    for (auto& sel : m_editor.m_selections)
    {
        BufferIterator position = sel.last();
        String content = string;
        m_editor.filters()(buffer, position, content);
        m_editor.buffer().insert(position, content);
    }
}

void IncrementalInserter::insert(const memoryview<String>& strings)
{
    m_editor.insert(strings);
}

void IncrementalInserter::erase()
{
    for (auto& sel : m_editor.m_selections)
    {
        BufferIterator pos = sel.last();
        m_editor.buffer().erase(utf8::previous(pos), pos);
    }
}

void IncrementalInserter::move_cursors(const BufferCoord& offset)
{
    for (auto& sel : m_editor.m_selections)
    {
        BufferCoord pos = m_editor.m_buffer->line_and_column_at(sel.last());
        BufferIterator it = m_editor.m_buffer->iterator_at(pos + offset);
        sel = Selection(it, it);
    }
}

}
<|endoftext|>


<commit_before>#ifndef SDLAB_H
#define SDLAB_H

#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <errors.h>
#include <stdlib.h>
#include <math.h>
#include <unistd.h>
#include <termios.h>
#include <time.h>
#include <float.h>

#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/ioctl.h>
#include <netdb.h>

#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <dirent.h>

#include <vector>
#include <complex>

using namespace std;
typedef std::complex<double> sdlab_complex;

#endif

#define POINT_1SEC 2097152

int main()
{
  int i;
  double noise;
  double p_signal = 1.0;
  int f01k = 64;//Hz
  int f02k = 128;//Hz
  int f04k = 256;//Hz
  int f08k = 512;//Hz
  int f16k = 1024;//Hz
  int f32k = 16384;//Hz
  int f64k = 32768;//Hz

  int id = 0;
  int flag = 0;

  int sock;
  struct sockaddr_in addr0, addr1;

  sock = socket(AF_INET, SOCK_DGRAM, 0);

  addr0.sin_family = AF_INET;
  addr0.sin_port = htons(0x4000);
  addr0.sin_addr.s_addr = inet_addr("127.0.0.1");

  addr1.sin_family = AF_INET;
  addr1.sin_port = htons(0x4001);
  addr1.sin_addr.s_addr = inet_addr("127.0.0.1");

  srand(0);

  while(1){
    id = 0;
    for(i = 0; i < POINT_1SEC; i++){
      double s;
      double s01k, s02k, s04k, s08k, s16k, s32k, s64k;
      unsigned short val;
      unsigned char buf[2048];

      noise = rand();
      noise = noise / (double)RAND_MAX;
      noise = noise * 18.0 - 9.0;

      s01k = p_signal
        * cos(2 * M_PI * ((double) f01k * i) /  (double) POINT_1SEC);
      s02k = p_signal
        * cos(2 * M_PI * ((double) f02k * i) /  (double) POINT_1SEC);
      s04k = p_signal
        * cos(2 * M_PI * ((double) f04k * i) /  (double) POINT_1SEC);
      s08k = p_signal
        * cos(2 * M_PI * ((double) f08k * i) /  (double) POINT_1SEC);
      s16k = p_signal
        * cos(2 * M_PI * ((double) f16k * i) /  (double) POINT_1SEC);
      s32k = p_signal
        * cos(2 * M_PI * ((double) f32k * i) /  (double) POINT_1SEC);
      s64k = p_signal
        * cos(2 * M_PI * ((double) f64k * i) /  (double) POINT_1SEC);
//      s = s01k + s02k + s04k + s08k + s16k + s32k + s64k + noise;

      s = (s01k + s02k + s04k + s08k + s16k + s32k + s64k + noise) / 16 *
        32767.0 + 32767.0;
//      s = s64k * ;
//      s = s + 71.0;
//      printf("%f\n", s);
      val = (unsigned short) (s);
//      printf("%05d %d\n", val, 4 + (i % 512) * 2);
      *((unsigned short *) (buf + 4 + (i % 512) * 2)) = htons(val);

      if((i + 1) % 512 == 0){
        int ret;
        *((int *) buf) = htonl(id);
        id += 512;
//        printf("id = %d, size = %d\n", id, sizeof(buf));

        if(flag == 0){
          ret = sendto(sock, buf, 1028, 0,
                       (struct sockaddr *)&addr0, sizeof(addr0));
        }else{
          ret = sendto(sock, buf, 1028, 0,
                       (struct sockaddr *)&addr1, sizeof(addr0));
        }

//        printf("ret = %d\n", ret);
//        exit(0);
      }
    }

    if(flag == 0){
      flag = 1;
    }else{
      flag = 0;
      printf("sleep\n");
      sleep(1);
    }
  }
}
<commit_msg>bugfix unsigned -> signed<commit_after>#ifndef SDLAB_H
#define SDLAB_H

#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <errors.h>
#include <stdlib.h>
#include <math.h>
#include <unistd.h>
#include <termios.h>
#include <time.h>
#include <float.h>

#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/ioctl.h>
#include <netdb.h>

#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <dirent.h>

#include <vector>
#include <complex>

using namespace std;
typedef std::complex<double> sdlab_complex;

#endif

#define POINT_1SEC 2097152

int main()
{
  int i;
  double noise;
  double p_signal = 1.0;
  int f01k = 64;//Hz
  int f02k = 128;//Hz
  int f04k = 256;//Hz
  int f08k = 512;//Hz
  int f16k = 1024;//Hz
  int f32k = 16384;//Hz
  int f64k = 32768;//Hz

  int id = 0;
  int flag = 0;

  int sock;
  struct sockaddr_in addr0, addr1;

  sock = socket(AF_INET, SOCK_DGRAM, 0);

  addr0.sin_family = AF_INET;
  addr0.sin_port = htons(0x4000);
  addr0.sin_addr.s_addr = inet_addr("127.0.0.1");

  addr1.sin_family = AF_INET;
  addr1.sin_port = htons(0x4001);
  addr1.sin_addr.s_addr = inet_addr("127.0.0.1");

  srand(0);

  while(1){
    id = 0;
    for(i = 0; i < POINT_1SEC; i++){
      double s;
      double s01k, s02k, s04k, s08k, s16k, s32k, s64k;
      unsigned short val;
      unsigned char buf[2048];

      noise = rand();
      noise = noise / (double)RAND_MAX;
      noise = noise * 18.0 - 9.0;

      s01k = p_signal
        * cos(2 * M_PI * ((double) f01k * i) /  (double) POINT_1SEC);
      s02k = p_signal
        * cos(2 * M_PI * ((double) f02k * i) /  (double) POINT_1SEC);
      s04k = p_signal
        * cos(2 * M_PI * ((double) f04k * i) /  (double) POINT_1SEC);
      s08k = p_signal
        * cos(2 * M_PI * ((double) f08k * i) /  (double) POINT_1SEC);
      s16k = p_signal
        * cos(2 * M_PI * ((double) f16k * i) /  (double) POINT_1SEC);
      s32k = p_signal
        * cos(2 * M_PI * ((double) f32k * i) /  (double) POINT_1SEC);
      s64k = p_signal
        * cos(2 * M_PI * ((double) f64k * i) /  (double) POINT_1SEC);
//      s = s01k + s02k + s04k + s08k + s16k + s32k + s64k + noise;

      s = (s01k + s02k + s04k + s08k + s16k + s32k + s64k + noise) / 8 *
        32767.0;
//      s = s64k * ;
//      s = s + 71.0;
//      printf("%f\n", s);
      val = (unsigned short) (s);
//      printf("%05d %d\n", val, 4 + (i % 512) * 2);
      *((unsigned short *) (buf + 4 + (i % 512) * 2)) = htons(val);

      if((i + 1) % 512 == 0){
        int ret;
        *((int *) buf) = htonl(id);
        id += 512;
//        printf("id = %d, size = %d\n", id, sizeof(buf));

        if(flag == 0){
          ret = sendto(sock, buf, 1028, 0,
                       (struct sockaddr *)&addr0, sizeof(addr0));
        }else{
          ret = sendto(sock, buf, 1028, 0,
                       (struct sockaddr *)&addr1, sizeof(addr0));
        }

//        printf("ret = %d\n", ret);
//        exit(0);
      }
    }

    if(flag == 0){
      flag = 1;
    }else{
      flag = 0;
      printf("sleep\n");
      sleep(1);
    }
  }
}
<|endoftext|>


<commit_before>#include <iostream>
#include "search.cc"
#include <string>
#include <assert.h>

using namespace std;

int main(){
	int SA[] = {11, 10, 7, 4, 1, 0, 9, 8, 6, 3, 5, 2};
	string S = "mississippi$";
	int LCP[] = {-1, 0, 1, 1, 4, 0, 0, 1, 0, 2, 1, 3};
	int ISA[] = {5, 4, 11, 9, 3, 10, 8, 2, 7, 6, 1, 0};
	char c = 'i';

	assert(1 == binary_search_left(c, {0, 0, 11}, S, SA));
	assert(4 == binary_search_right(c, { 0, 0, 11}, S, SA));
	cout << "Test passed. (binary search)" << endl;

	interval_t ret_val = topdown(c, {0, 0, 11}, S, SA);
	assert (ret_val.depth == 1);
	assert (ret_val.start == 1);
	assert (ret_val.end == 4);
	cout << "Test passed. (topdown search)" << endl;

	interval_t empty, interval;

	c = 's';
	ret_val = topdown(c, {1, 3, 4}, S, SA);
	assert (ret_val.depth == 2);
	assert (ret_val.start == 3);
	assert (ret_val.end == 4);
	cout << "Test passed. (topdown search)" << endl;

	// missIppi
	c = 'i';
	ret_val = topdown(c, {3, 3, 4}, S, SA);
	assert (ret_val.depth == 4);
	assert (ret_val.start == 3);
	assert (ret_val.end == 4);
	cout << "Test passed. (topdown search)" << endl;

	// missiPpi
	c = 'p';
	ret_val = topdown(c, {4, 3, 4}, S, SA);
	assert (ret_val.depth == 5);
	assert (ret_val.start == 3);
	assert (ret_val.end == 3);
	cout << "Test passed. (topdown search)" << endl;

	// issiPpi
	string stringg("issippi$");
	ret_val = traverse (0 , {0, 0, 11}, 14, S, SA, stringg);
	assert (ret_val.depth == 8);
	assert (ret_val.start == 3);
	assert (ret_val.end == 3);
	cout << "Test passed. (topdown search)" << endl;

	//////////////////////////
	// array tests:
	cout << "Full MEM test (1), suffix array" << endl;
	string query_string ("issip");
	// K == 1 (step), N == size of S (11), L = min match to print (npr. 2)
	MEM(0, S, ISA, LCP, SA, query_string, 1, 11, 2);

	cout << "Full MEM test (2), sparse suffix array" << endl;
	////// Sparse
	int sparse_SA[] = {10, 4, 0, 8, 6, 2};
	string string_S = "mississippi$";
	int sparse_ISA[] = {2, 5, 1, 4, 3, 0};
	int sparse_LCP[] = {-1, 1, 0, 0, 0, 1};
	int K = 2;
	int L = 3;

	MEM(0, string_S, sparse_ISA, sparse_LCP, sparse_SA, query_string, K, string_S.length(), L);

	cout << "Full MEM test (3), sparse suffix array" << endl;
	int SA_a[]  =  {70,45,15,40,10,65,35,5,60,30,0,55,25,50,20};
  int ISA_a []= { 10, 7, 4, 2,14,12,9,6,3,1,13,11,8,5,0};
  int LCP_a []= {  -1 ,0  ,25   ,1  ,30   ,0   ,5  ,35   ,2  ,10  ,40   ,1  ,15   ,0  ,20 };
	query_string = "CTAACCCTAACCCTAACCCTAACCCTAACCCTAA";
	S = "CCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTA";
	K = 5; L = 30;

	MEM(0, S, ISA_a, LCP_a, SA_a, query_string, K, string_S.length(), L );
	return 0;

}

<commit_msg>preatty code (3) :)<commit_after>#include <iostream>
#include "search.cc"
#include <string>
#include <assert.h>

using namespace std;

int main(){
  // Regual suffix array
	int SA[] = {11, 10, 7, 4, 1, 0, 9, 8, 6, 3, 5, 2};
	string S = "mississippi$";
	int LCP[] = {-1, 0, 1, 1, 4, 0, 0, 1, 0, 2, 1, 3};
	int ISA[] = {5, 4, 11, 9, 3, 10, 8, 2, 7, 6, 1, 0};
	char c = 'i';

	assert(1 == binary_search_left(c, {0, 0, 11}, S, SA));
	assert(4 == binary_search_right(c, { 0, 0, 11}, S, SA));
	cout << "Test passed. (binary search)" << endl;

	interval_t ret_val = topdown(c, {0, 0, 11}, S, SA);
	assert (ret_val.depth == 1);
	assert (ret_val.start == 1);
	assert (ret_val.end == 4);
	cout << "Test passed. (topdown search)" << endl;

	interval_t empty, interval;
	c = 's';
	ret_val = topdown(c, {1, 3, 4}, S, SA);
	assert (ret_val.depth == 2);
	assert (ret_val.start == 3);
	assert (ret_val.end == 4);
	cout << "Test passed. (topdown search)" << endl;

	// missIppi
	c = 'i';
	ret_val = topdown(c, {3, 3, 4}, S, SA);
	assert (ret_val.depth == 4);
	assert (ret_val.start == 3);
	assert (ret_val.end == 4);
	cout << "Test passed. (topdown search)" << endl;

	// missiPpi
	c = 'p';
	ret_val = topdown(c, {4, 3, 4}, S, SA);
	assert (ret_val.depth == 5);
	assert (ret_val.start == 3);
	assert (ret_val.end == 3);
	cout << "Test passed. (topdown search)" << endl;

	// issiPpi
	string stringg("issippi$");
	ret_val = traverse (0 , {0, 0, 11}, 14, S, SA, stringg);
	assert (ret_val.depth == 8);
	assert (ret_val.start == 3);
	assert (ret_val.end == 3);
	cout << "Test passed. (topdown search)" << endl;

	// Array tests
	cout << "Full MEM test (1), suffix array" << endl;
	string query_string ("issip");
	// K == 1 (step), N == size of S (11), L = min match to print (npr. 2)
	MEM(0, S, ISA, LCP, SA, query_string, 1, 11, 2);

	// Sparse
	cout << "Full MEM test (2), sparse suffix array" << endl;
	int sparse_SA[] = {10, 4, 0, 8, 6, 2};
	string string_S = "mississippi$";
	int sparse_ISA[] = {2, 5, 1, 4, 3, 0};
	int sparse_LCP[] = {-1, 1, 0, 0, 0, 1};
	int K = 2;
	int L = 3;
	MEM(0, string_S, sparse_ISA, sparse_LCP, sparse_SA, query_string, K, string_S.length(), L);

	// Sparse 2
	cout << "Full MEM test (3), sparse suffix array" << endl;
	int SA_a[]  =  {70,45,15,40,10,65,35,5,60,30,0,55,25,50,20};
  int ISA_a []= { 10, 7, 4, 2,14,12,9,6,3,1,13,11,8,5,0};
  int LCP_a []= {  -1 ,0  ,25   ,1  ,30   ,0   ,5  ,35   ,2  ,10  ,40   ,1  ,15   ,0  ,20 };
	query_string = "CTAACCCTAACCCTAACCCTAACCCTAACCCTAA";
	S = "CCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTA";
	K = 5; L = 30;
	MEM(0, S, ISA_a, LCP_a, SA_a, query_string, K, string_S.length(), L );

return 0;
}

<|endoftext|>


<commit_before>/**************************************************************************
**
** This file is part of Doxygen plugin for Qt Creator
**
** Copyright (c) 2009 Kevin Tanguy (kofee@kofee.org).
**
** This plugin is free software: you can redistribute it and/or modify
** it under the terms of the GNU Lesser General Public License as
** published by the Free Software Foundation, either version 2.1
** of the License, or (at your option) any later version.
**
** This plugin is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
** GNU Lesser General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with Doxygen Plugin. If not, see <http://www.gnu.org/licenses/>.
**/

#include "doxygen.h"

#include <QObject>
#include <plugins/cppeditor/cppeditorconstants.h>
#include <plugins/cpptools/cpptoolsconstants.h>
#include <plugins/cpptools/cppmodelmanagerinterface.h>
#include <plugins/texteditor/basetexteditor.h>
#include <plugins/coreplugin/icore.h>
#include <plugins/coreplugin/uniqueidmanager.h>
#include <plugins/coreplugin/mimedatabase.h>
#include <plugins/coreplugin/actionmanager/actionmanager.h>
#include <plugins/coreplugin/editormanager/ieditor.h>
#include <plugins/coreplugin/editormanager/editormanager.h>
#include <plugins/projectexplorer/project.h>
#include <plugins/projectexplorer/projectexplorer.h>
#include <plugins/projectexplorer/session.h>
#include <plugins/projectexplorer/projectexplorerconstants.h>

#include <libs/cplusplus/Overview.h>
#include <libs/extensionsystem/pluginmanager.h>
#include <shared/cplusplus/Scope.h>
#include <shared/cplusplus/Symbols.h>
#include <shared/cplusplus/Names.h>
#include <cplusplus/CppDocument.h>
#include <cplusplus/CppBindings.h>

#include <QString>
#include <QStringList>
#include <QFile>
#include <QFileInfo>
#include <QDebug>
#include <QRegExp>

using namespace CPlusPlus;
using namespace ProjectExplorer;
using namespace DoxyPlugin;
using namespace DoxyPlugin::Internal;

Doxygen* Doxygen::m_instance = 0;

Doxygen::Doxygen()
{
}

Doxygen* Doxygen::instance()
{
    if (!m_instance)
        m_instance = new Doxygen();
    return m_instance;
}

// TODO, get rid of it.
QStringList scopesForSymbol(const Symbol* symbol)
{
    Scope *scope = symbol->scope();
    QStringList scopes;

    if(symbol->isFunction())
    {
        const Name *name = symbol->name();
        Overview overview;
        overview.setShowArgumentNames(false);
        overview.setShowReturnTypes(false);
        scopes.prepend(overview.prettyName(name));
        return scopes;
    }

    for (; scope; scope = scope->enclosingScope())
    {
        Symbol *owner = scope->owner();

        if (owner && owner->name() && ! scope->isEnumScope())
        {
            const Name *name = owner->name();
            Overview overview;
            overview.setShowArgumentNames(false);
            overview.setShowReturnTypes(false);
            scopes.prepend(overview.prettyName(name));
        }
    }
    return scopes;
}

Symbol* currentSymbol(Core::IEditor *editor)
{
    int line = editor->currentLine();
    int column = editor->currentColumn();

    CppTools::CppModelManagerInterface *modelManager =
            ExtensionSystem::PluginManager::instance()->getObject<CppTools::CppModelManagerInterface>();
    if (!modelManager)
        return 0;
    const Snapshot snapshot = modelManager->snapshot();
    Document::Ptr doc = snapshot.document(editor->file()->fileName());
    if (!doc)
        return 0;
    return doc->findSymbolAt(line, column);
}

// TODO, recode it entirely.
void Doxygen::createDocumentation(const DoxygenSettingsStruct &DoxySettings)
{
    const Core::EditorManager *editorManager = Core::EditorManager::instance();
    Core::IEditor *editor = editorManager->currentEditor();

    // before continuing, test if the editor is actually showing a file.
    if(!editor) return;

    // get the widget for later.
    TextEditor::BaseTextEditor *editorWidget = qobject_cast<TextEditor::BaseTextEditor*>(
            editorManager->currentEditor()->widget());

    // TODO, only do that if class and verbosePrinting
    // Catch hold of the plugin-manager
    ExtensionSystem::PluginManager* pm
            = ExtensionSystem::PluginManager::instance();
    // Look for the ProjectExplorerPlugin object
    ProjectExplorer::ProjectExplorerPlugin* projectExplorerPlugin
            = pm->getObject<ProjectExplorer::ProjectExplorerPlugin>();
    // Fetch a list of all open projects
    QList<ProjectExplorer::Project*> projects
            = projectExplorerPlugin->session()->projects();
    // Project root directory
    QString projectRoot;

    // Attempt to find our project
    Q_FOREACH(ProjectExplorer::Project* project, projects)
    {
        QStringList files = project->files(Project::ExcludeGeneratedFiles); // ProjectExplorer::Project::FilesMode::ExcludeGeneratedFiles
        // is it our project ?
        if(files.contains(editor->file()->fileName()))
        {
            // YES! get the .pro and remove the directory part from our filename
            // TODO, check if it is smart... (it's not really.)
            Q_FOREACH(QString f, files)
            {
                if(f.contains(QRegExp(".pro$")))
                {
                    projectRoot = f.section('/', 0, -2);
                    if(projectRoot.size()) projectRoot.append("/");
                    continue;
                }
            }
            if(projectRoot.size()) continue;
        }
    }

    Symbol *lastSymbol = currentSymbol(editor);
    if (!lastSymbol || !lastSymbol->scope())
        return;

    QStringList scopes = scopesForSymbol(lastSymbol);
    Overview overview;
    overview.setShowArgumentNames(true);
    overview.setShowReturnTypes(true);
    overview.setShowFullyQualifiedNamed(true);
    overview.setShowFunctionSignatures(true);
    const Name *name = lastSymbol->name();
    scopes.append(overview.prettyName(name));

    QString docToWrite;

    // Do we print a short documentation block at end of line?
    bool printAtEnd = false;

    // Get current indentation as per bug #5
    QString indent;
    editorWidget->moveCursor(QTextCursor::StartOfLine);
    editorWidget->gotoLineEndWithSelection();
    QString currentText = editorWidget->textCursor().selectedText();
    QStringList textList = currentText.split(QRegExp("\\b"));
    indent = textList.at(0);
    if(indent.endsWith('~'))
    {
        indent.chop(1);
    }

    if(lastSymbol->isClass())
    {
        docToWrite += indent + DoxySettings.DoxyComment.doxBegin;
        if(DoxySettings.printBrief)
        {
            docToWrite += indent + DoxySettings.DoxyComment.doxBrief;
            docToWrite += indent + DoxySettings.DoxyComment.doxEmptyLine;
        }
        if(DoxySettings.verbosePrinting)
        {
            QString fileName = editor->file()->fileName().remove(0, editor->file()->fileName().lastIndexOf("/") + 1);
            QString fileNameProj = editor->file()->fileName().remove(projectRoot);
            docToWrite += indent + DoxySettings.DoxyComment.doxNewLine + "class " + overview.prettyName(name) + " " + fileName + " \"" + fileNameProj + "\"\n";
        }
        docToWrite += indent + DoxySettings.DoxyComment.doxEnding;
    }
    else if(lastSymbol->isTypedef())
    {
        docToWrite += indent + DoxySettings.DoxyComment.doxBegin;
        if(DoxySettings.printBrief)
        {
            docToWrite += indent + DoxySettings.DoxyComment.doxBrief;
            docToWrite += indent + DoxySettings.DoxyComment.doxEmptyLine;
        }
        if(DoxySettings.verbosePrinting)
            docToWrite += indent + DoxySettings.DoxyComment.doxNewLine + "typedef " + overview.prettyName(name);
        docToWrite += indent + DoxySettings.DoxyComment.doxEnding;
    }
    else if(lastSymbol->isEnum())
    {
        docToWrite += indent + DoxySettings.DoxyComment.doxBegin;
        if(DoxySettings.printBrief)
            docToWrite += indent + DoxySettings.DoxyComment.doxBrief;
        docToWrite += indent + DoxySettings.DoxyComment.doxEmptyLine;
        if(DoxySettings.verbosePrinting)
            docToWrite += indent + DoxySettings.DoxyComment.doxNewLine + "enum " + overview.prettyName(name) + "\n";
        docToWrite += DoxySettings.DoxyComment.doxEnding;
    }
    // Here comes the bitch.
    else if(lastSymbol->isDeclaration() || lastSymbol->isFunction())
    {
        overview.setShowArgumentNames(true);
        overview.setShowReturnTypes(false);
        overview.setShowFullyQualifiedNamed(true);
        overview.setShowFunctionSignatures(true);
        QString arglist = overview.prettyType(lastSymbol->type(), name);

        docToWrite += indent + DoxySettings.DoxyComment.doxBegin;
        if(DoxySettings.printBrief)
        {
            docToWrite += indent + DoxySettings.DoxyComment.doxBrief;
            docToWrite += indent + DoxySettings.DoxyComment.doxEmptyLine;
        }

        // if variable, do it quickly...
        if(!arglist.contains('('))
        {
            if(DoxySettings.shortVarDoc)
            {
                printAtEnd = true;
                docToWrite = DoxySettings.DoxyComment.doxShortVarDoc + "TODO */";
            }
            else
            {
                if(DoxySettings.verbosePrinting)
                    docToWrite += indent + DoxySettings.DoxyComment.doxNewLine + "var " + overview.prettyName(name) + "\n" + indent + DoxySettings.DoxyComment.doxEnding;
                else
                    docToWrite += indent + DoxySettings.DoxyComment.doxEmptyLine + indent + DoxySettings.DoxyComment.doxEnding;
            }
        }
        else
        {
            // Never noticed it before, a useless comment block because of the Q_OBJECT macro
            // so let's just ignore that will we?
            if(overview.prettyName(name) == "qt_metacall")
                return;

            if(DoxySettings.verbosePrinting)
                docToWrite += indent + DoxySettings.DoxyComment.doxNewLine + "fn " + overview.prettyName(name) + "\n";

            // Check parameters
            // Do it the naive way first before finding better in the API
            qDebug() << arglist;
            arglist.remove(0, arglist.indexOf("(") + 1);
            arglist.remove(arglist.lastIndexOf(")"), arglist.size() - arglist.lastIndexOf(")"));
            int indexfrom, indexto;
            while( ((indexfrom = arglist.indexOf('<'))!= -1) && ((indexto = arglist.indexOf('>')) != -1) )
            {
                arglist.remove(indexfrom, indexto - indexfrom + 1);
            }
            QStringList args = arglist.trimmed().split(',', QString::SkipEmptyParts);

            Q_FOREACH(QString singleArg, args)
            {
                singleArg.remove(QRegExp("\\s*=.*")); // FIXME probably don't need the * after \\s but...
                singleArg.replace("*","");
                singleArg.replace("&","");
                docToWrite += indent + DoxySettings.DoxyComment.doxNewLine + "param " + singleArg.section(' ',  -1) + "\n";
            }

            // And now check the return type
            overview.setShowArgumentNames(false);
            overview.setShowReturnTypes(true);
            overview.setShowFullyQualifiedNamed(false);
            overview.setShowFunctionSignatures(false);

            arglist = overview.prettyType(lastSymbol->type(), name);

            // FIXME this check is just insane...
            if( arglist.contains(' ') && (((overview.prettyName(name) != scopes.front()) && (overview.prettyName(name).at(0) != '~')) || (lastSymbol->isFunction() && !overview.prettyName(name).contains("::~"))) )
            {
                //qDebug() << arglist;
                QRegExp rx("void *");
                rx.setPatternSyntax(QRegExp::Wildcard);
                if(!rx.exactMatch(arglist))
                {
                    // dirty workarround
                    int last;
                    if(arglist.contains('>'))
                        last = arglist.lastIndexOf('>') + 1;
                    else
                        last = arglist.lastIndexOf(' ');

                    arglist.chop(arglist.size() - last);
                    docToWrite += indent + DoxySettings.DoxyComment.doxNewLine + "return " +  arglist + "\n";
                }

            }
            docToWrite += indent + DoxySettings.DoxyComment.doxEnding;
        }
    }

    // Write the documentation in the editor
    if (editorWidget)
    {
        if(printAtEnd)
            editorWidget->moveCursor(QTextCursor::EndOfLine);
        else
            editorWidget->moveCursor(QTextCursor::StartOfBlock);
        editorWidget->insertPlainText(docToWrite);
    }

}

void Doxygen::addSymbol(const CPlusPlus::Symbol* symbol, QMap<unsigned, const CPlusPlus::Symbol*> &symmap)
{
    if(!symbol) return;

    if(symbol->isArgument()
        ||symbol->isFunction()
        || symbol->isDeclaration()
        || symbol->isEnum())
        {
        symmap.insert(symbol->line(), symbol);
        return;
    }
    else if(symbol->isForwardClassDeclaration()
        || symbol->isExtern()
        || symbol->isFriend()
        || symbol->isGenerated()
        || symbol->isUsingNamespaceDirective()
        || symbol->isUsingDeclaration()
        )
        {
        return;
    }
    symmap.insert(symbol->line(), symbol);

    const CPlusPlus::ScopedSymbol *scopedSymbol = symbol->asScopedSymbol();
    if (scopedSymbol)
    {
        CPlusPlus::Scope *scope = scopedSymbol->members();
        if (scope)
        {
            CPlusPlus::Scope::iterator cur = scope->firstSymbol();
            while (cur != scope->lastSymbol())
            {
                const CPlusPlus::Symbol *curSymbol = *cur;
                ++cur;
                if (!curSymbol)
                    continue;
                addSymbol(curSymbol, symmap);
            }
        }
    }

}

void Doxygen::documentFile(const DoxygenSettingsStruct &DoxySettings)
{
    const Core::EditorManager *editorManager = Core::EditorManager::instance();
    Core::IEditor *editor = editorManager->currentEditor();

    // before continuing, test if the editor is actually showing a file.
    if(!editor)
        return;

    CppTools::CppModelManagerInterface *modelManager =
            ExtensionSystem::PluginManager::instance()->getObject<CppTools::CppModelManagerInterface>();
    if(!modelManager)
        return;

    const Snapshot snapshot = modelManager->snapshot();
    Document::Ptr doc = snapshot.document(editor->file()->fileName());
    if (!doc)
        return;

    Scope *scope = doc->globalSymbols();
    if(!scope)
        return;

    unsigned symbolcount = scope->symbolCount();

    QMap<unsigned, const Symbol*> symmap;
    for(unsigned i = 0; i < symbolcount; ++i)
        addSymbol(scope->symbolAt(i), symmap);

    TextEditor::BaseTextEditor *editorWidget = qobject_cast<TextEditor::BaseTextEditor*>(
            editorManager->currentEditor()->widget());

    if (editorWidget)
    {
        QMap<unsigned, const Symbol*>::iterator it = symmap.end();
        for(; it != symmap.begin(); --it)
        {
            unsigned line = (it-1).key();
            editorWidget->gotoLine(line);
            createDocumentation(DoxySettings);
        }
    }
}

<commit_msg>Quick minor fix. (class end, namespace end weirdness)<commit_after>/**************************************************************************
**
** This file is part of Doxygen plugin for Qt Creator
**
** Copyright (c) 2009 Kevin Tanguy (kofee@kofee.org).
**
** This plugin is free software: you can redistribute it and/or modify
** it under the terms of the GNU Lesser General Public License as
** published by the Free Software Foundation, either version 2.1
** of the License, or (at your option) any later version.
**
** This plugin is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
** GNU Lesser General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with Doxygen Plugin. If not, see <http://www.gnu.org/licenses/>.
**/

#include "doxygen.h"

#include <QObject>
#include <plugins/cppeditor/cppeditorconstants.h>
#include <plugins/cpptools/cpptoolsconstants.h>
#include <plugins/cpptools/cppmodelmanagerinterface.h>
#include <plugins/texteditor/basetexteditor.h>
#include <plugins/coreplugin/icore.h>
#include <plugins/coreplugin/uniqueidmanager.h>
#include <plugins/coreplugin/mimedatabase.h>
#include <plugins/coreplugin/actionmanager/actionmanager.h>
#include <plugins/coreplugin/editormanager/ieditor.h>
#include <plugins/coreplugin/editormanager/editormanager.h>
#include <plugins/projectexplorer/project.h>
#include <plugins/projectexplorer/projectexplorer.h>
#include <plugins/projectexplorer/session.h>
#include <plugins/projectexplorer/projectexplorerconstants.h>

#include <libs/cplusplus/Overview.h>
#include <libs/extensionsystem/pluginmanager.h>
#include <shared/cplusplus/Scope.h>
#include <shared/cplusplus/Symbols.h>
#include <shared/cplusplus/Names.h>
#include <cplusplus/CppDocument.h>
#include <cplusplus/CppBindings.h>

#include <QString>
#include <QStringList>
#include <QFile>
#include <QFileInfo>
//#include <QDebug>
#include <QRegExp>

using namespace CPlusPlus;
using namespace ProjectExplorer;
using namespace DoxyPlugin;
using namespace DoxyPlugin::Internal;

Doxygen* Doxygen::m_instance = 0;

Doxygen::Doxygen()
{
}

Doxygen* Doxygen::instance()
{
    if (!m_instance)
        m_instance = new Doxygen();
    return m_instance;
}

// TODO, get rid of it.
QStringList scopesForSymbol(const Symbol* symbol)
{
    Scope *scope = symbol->scope();
    QStringList scopes;

    if(symbol->isFunction())
    {
        const Name *name = symbol->name();
        Overview overview;
        overview.setShowArgumentNames(false);
        overview.setShowReturnTypes(false);
        scopes.prepend(overview.prettyName(name));
        return scopes;
    }

    for (; scope; scope = scope->enclosingScope())
    {
        Symbol *owner = scope->owner();

        if (owner && owner->name() && ! scope->isEnumScope())
        {
            const Name *name = owner->name();
            Overview overview;
            overview.setShowArgumentNames(false);
            overview.setShowReturnTypes(false);
            scopes.prepend(overview.prettyName(name));
        }
    }
    return scopes;
}

Symbol* currentSymbol(Core::IEditor *editor)
{
    int line = editor->currentLine();
    int column = editor->currentColumn();

    CppTools::CppModelManagerInterface *modelManager =
            ExtensionSystem::PluginManager::instance()->getObject<CppTools::CppModelManagerInterface>();
    if (!modelManager)
        return 0;
    const Snapshot snapshot = modelManager->snapshot();
    Document::Ptr doc = snapshot.document(editor->file()->fileName());
    if (!doc)
        return 0;
    return doc->findSymbolAt(line, column);
}

// TODO, recode it entirely.
void Doxygen::createDocumentation(const DoxygenSettingsStruct &DoxySettings)
{
    const Core::EditorManager *editorManager = Core::EditorManager::instance();
    Core::IEditor *editor = editorManager->currentEditor();

    // before continuing, test if the editor is actually showing a file.
    if(!editor) return;

    // get the widget for later.
    TextEditor::BaseTextEditor *editorWidget = qobject_cast<TextEditor::BaseTextEditor*>(
            editorManager->currentEditor()->widget());

    // TODO, only do that if class and verbosePrinting
    // Catch hold of the plugin-manager
    ExtensionSystem::PluginManager* pm
            = ExtensionSystem::PluginManager::instance();
    // Look for the ProjectExplorerPlugin object
    ProjectExplorer::ProjectExplorerPlugin* projectExplorerPlugin
            = pm->getObject<ProjectExplorer::ProjectExplorerPlugin>();
    // Fetch a list of all open projects
    QList<ProjectExplorer::Project*> projects
            = projectExplorerPlugin->session()->projects();
    // Project root directory
    QString projectRoot;

    // Attempt to find our project
    Q_FOREACH(ProjectExplorer::Project* project, projects)
    {
        QStringList files = project->files(Project::ExcludeGeneratedFiles); // ProjectExplorer::Project::FilesMode::ExcludeGeneratedFiles
        // is it our project ?
        if(files.contains(editor->file()->fileName()))
        {
            // YES! get the .pro and remove the directory part from our filename
            // TODO, check if it is smart... (it's not really.)
            Q_FOREACH(QString f, files)
            {
                if(f.contains(QRegExp(".pro$")))
                {
                    projectRoot = f.section('/', 0, -2);
                    if(projectRoot.size()) projectRoot.append("/");
                    continue;
                }
            }
            if(projectRoot.size()) continue;
        }
    }

    Symbol *lastSymbol = currentSymbol(editor);
    if (!lastSymbol || !lastSymbol->scope())
        return;

    QStringList scopes = scopesForSymbol(lastSymbol);
    Overview overview;
    overview.setShowArgumentNames(true);
    overview.setShowReturnTypes(true);
    overview.setShowFullyQualifiedNamed(true);
    overview.setShowFunctionSignatures(true);
    const Name *name = lastSymbol->name();
    scopes.append(overview.prettyName(name));

    QString docToWrite;

    // Do we print a short documentation block at end of line?
    bool printAtEnd = false;

    // Get current indentation as per bug #5
    QString indent;
    editorWidget->moveCursor(QTextCursor::StartOfLine);
    editorWidget->gotoLineEndWithSelection();
    QString currentText = editorWidget->textCursor().selectedText();
    QStringList textList = currentText.split(QRegExp("\\b"));
    indent = textList.at(0);
    // quickfix when calling the method o n"};" (end class) or "}" (end namespace)
    if(indent.contains(QRegExp("^\\};?")))
        return;
    if(indent.endsWith('~'))
    {
        indent.chop(1);
    }

    if(lastSymbol->isClass())
    {
        docToWrite += indent + DoxySettings.DoxyComment.doxBegin;
        if(DoxySettings.printBrief)
        {
            docToWrite += indent + DoxySettings.DoxyComment.doxBrief;
            docToWrite += indent + DoxySettings.DoxyComment.doxEmptyLine;
        }
        if(DoxySettings.verbosePrinting)
        {
            QString fileName = editor->file()->fileName().remove(0, editor->file()->fileName().lastIndexOf("/") + 1);
            QString fileNameProj = editor->file()->fileName().remove(projectRoot);
            docToWrite += indent + DoxySettings.DoxyComment.doxNewLine + "class " + overview.prettyName(name) + " " + fileName + " \"" + fileNameProj + "\"\n";
        }
        docToWrite += indent + DoxySettings.DoxyComment.doxEnding;
    }
    else if(lastSymbol->isTypedef())
    {
        docToWrite += indent + DoxySettings.DoxyComment.doxBegin;
        if(DoxySettings.printBrief)
        {
            docToWrite += indent + DoxySettings.DoxyComment.doxBrief;
            docToWrite += indent + DoxySettings.DoxyComment.doxEmptyLine;
        }
        if(DoxySettings.verbosePrinting)
            docToWrite += indent + DoxySettings.DoxyComment.doxNewLine + "typedef " + overview.prettyName(name);
        docToWrite += indent + DoxySettings.DoxyComment.doxEnding;
    }
    else if(lastSymbol->isEnum())
    {
        docToWrite += indent + DoxySettings.DoxyComment.doxBegin;
        if(DoxySettings.printBrief)
            docToWrite += indent + DoxySettings.DoxyComment.doxBrief;
        docToWrite += indent + DoxySettings.DoxyComment.doxEmptyLine;
        if(DoxySettings.verbosePrinting)
            docToWrite += indent + DoxySettings.DoxyComment.doxNewLine + "enum " + overview.prettyName(name) + "\n";
        docToWrite += DoxySettings.DoxyComment.doxEnding;
    }
    // Here comes the bitch.
    else if(lastSymbol->isDeclaration() || lastSymbol->isFunction())
    {
        overview.setShowArgumentNames(true);
        overview.setShowReturnTypes(false);
        overview.setShowFullyQualifiedNamed(true);
        overview.setShowFunctionSignatures(true);
        QString arglist = overview.prettyType(lastSymbol->type(), name);

        docToWrite += indent + DoxySettings.DoxyComment.doxBegin;
        if(DoxySettings.printBrief)
        {
            docToWrite += indent + DoxySettings.DoxyComment.doxBrief;
            docToWrite += indent + DoxySettings.DoxyComment.doxEmptyLine;
        }

        // if variable, do it quickly...
        if(!arglist.contains('('))
        {
            if(DoxySettings.shortVarDoc)
            {
                printAtEnd = true;
                docToWrite = DoxySettings.DoxyComment.doxShortVarDoc + "TODO */";
            }
            else
            {
                if(DoxySettings.verbosePrinting)
                    docToWrite += indent + DoxySettings.DoxyComment.doxNewLine + "var " + overview.prettyName(name) + "\n" + indent + DoxySettings.DoxyComment.doxEnding;
                else
                    docToWrite += indent + DoxySettings.DoxyComment.doxEmptyLine + indent + DoxySettings.DoxyComment.doxEnding;
            }
        }
        else
        {
            // Never noticed it before, a useless comment block because of the Q_OBJECT macro
            // so let's just ignore that will we?
            if(overview.prettyName(name) == "qt_metacall")
                return;

            if(DoxySettings.verbosePrinting)
                docToWrite += indent + DoxySettings.DoxyComment.doxNewLine + "fn " + overview.prettyName(name) + "\n";

            // Check parameters
            // Do it the naive way first before finding better in the API
            arglist.remove(0, arglist.indexOf("(") + 1);
            arglist.remove(arglist.lastIndexOf(")"), arglist.size() - arglist.lastIndexOf(")"));
            int indexfrom, indexto;
            while( ((indexfrom = arglist.indexOf('<'))!= -1) && ((indexto = arglist.indexOf('>')) != -1) )
            {
                arglist.remove(indexfrom, indexto - indexfrom + 1);
            }
            QStringList args = arglist.trimmed().split(',', QString::SkipEmptyParts);

            Q_FOREACH(QString singleArg, args)
            {
                singleArg.remove(QRegExp("\\s*=.*")); // FIXME probably don't need the * after \\s but...
                singleArg.replace("*","");
                singleArg.replace("&","");
                docToWrite += indent + DoxySettings.DoxyComment.doxNewLine + "param " + singleArg.section(' ',  -1) + "\n";
            }

            // And now check the return type
            overview.setShowArgumentNames(false);
            overview.setShowReturnTypes(true);
            overview.setShowFullyQualifiedNamed(false);
            overview.setShowFunctionSignatures(false);

            arglist = overview.prettyType(lastSymbol->type(), name);

            // FIXME this check is just insane...
            if( arglist.contains(' ') && (((overview.prettyName(name) != scopes.front()) && (overview.prettyName(name).at(0) != '~')) || (lastSymbol->isFunction() && !overview.prettyName(name).contains("::~"))) )
            {
                //qDebug() << arglist;
                QRegExp rx("void *");
                rx.setPatternSyntax(QRegExp::Wildcard);
                if(!rx.exactMatch(arglist))
                {
                    // dirty workarround
                    int last;
                    if(arglist.contains('>'))
                        last = arglist.lastIndexOf('>') + 1;
                    else
                        last = arglist.lastIndexOf(' ');

                    arglist.chop(arglist.size() - last);
                    docToWrite += indent + DoxySettings.DoxyComment.doxNewLine + "return " +  arglist + "\n";
                }

            }
            docToWrite += indent + DoxySettings.DoxyComment.doxEnding;
        }
    }

    // Write the documentation in the editor
    if (editorWidget)
    {
        if(printAtEnd)
            editorWidget->moveCursor(QTextCursor::EndOfLine);
        else
            editorWidget->moveCursor(QTextCursor::StartOfBlock);
        editorWidget->insertPlainText(docToWrite);
    }

}

void Doxygen::addSymbol(const CPlusPlus::Symbol* symbol, QMap<unsigned, const CPlusPlus::Symbol*> &symmap)
{
    if(!symbol) return;

    if(symbol->isArgument()
        ||symbol->isFunction()
        || symbol->isDeclaration()
        || symbol->isEnum())
        {
        symmap.insert(symbol->line(), symbol);
        return;
    }
    else if(symbol->isForwardClassDeclaration()
        || symbol->isExtern()
        || symbol->isFriend()
        || symbol->isGenerated()
        || symbol->isUsingNamespaceDirective()
        || symbol->isUsingDeclaration()
        )
        {
        return;
    }
    symmap.insert(symbol->line(), symbol);

    const CPlusPlus::ScopedSymbol *scopedSymbol = symbol->asScopedSymbol();
    if (scopedSymbol)
    {
        CPlusPlus::Scope *scope = scopedSymbol->members();
        if (scope)
        {
            CPlusPlus::Scope::iterator cur = scope->firstSymbol();
            while (cur != scope->lastSymbol())
            {
                const CPlusPlus::Symbol *curSymbol = *cur;
                ++cur;
                if (!curSymbol)
                    continue;
                addSymbol(curSymbol, symmap);
            }
        }
    }

}

void Doxygen::documentFile(const DoxygenSettingsStruct &DoxySettings)
{
    const Core::EditorManager *editorManager = Core::EditorManager::instance();
    Core::IEditor *editor = editorManager->currentEditor();

    // before continuing, test if the editor is actually showing a file.
    if(!editor)
        return;

    CppTools::CppModelManagerInterface *modelManager =
            ExtensionSystem::PluginManager::instance()->getObject<CppTools::CppModelManagerInterface>();
    if(!modelManager)
        return;

    const Snapshot snapshot = modelManager->snapshot();
    Document::Ptr doc = snapshot.document(editor->file()->fileName());
    if (!doc)
        return;

    Scope *scope = doc->globalSymbols();
    if(!scope)
        return;

    unsigned symbolcount = scope->symbolCount();

    QMap<unsigned, const Symbol*> symmap;
    for(unsigned i = 0; i < symbolcount; ++i)
        addSymbol(scope->symbolAt(i), symmap);

    TextEditor::BaseTextEditor *editorWidget = qobject_cast<TextEditor::BaseTextEditor*>(
            editorManager->currentEditor()->widget());

    if (editorWidget)
    {
        QMap<unsigned, const Symbol*>::iterator it = symmap.end();
        for(; it != symmap.begin(); --it)
        {
            unsigned line = (it-1).key();
            editorWidget->gotoLine(line);
            createDocumentation(DoxySettings);
        }
    }
}

<|endoftext|>


<commit_before>/* dro project
 * this attempt is with lpc1343, using Olimex P1343 dev kit (8 LED's :)
 */
#include "quadraturecounter.h"
QuadratureCounter pos;//as in 'position'

#include "lpc13xx.h"
#include "gpio.h"
#include "nvic.h"

//shared ~millisecond services:
#include "systick.h"
using namespace SystemTimer;
#include "polledtimer.h"
#include "tableofpointers.h"

CyclicTimer ledToggle(750);//todo: clearer timebase
RegisterTimer(ledToggle);

#include "core_cmInstr.h"  //wfe OR wfi
#include "cruntime.h"

#include "p1343_board.h" //P1343devkit //for led's
#include "wtf.h"
using namespace LPC;

//should inherit from a board description header
const unsigned ExpectedClock=12000000;

// using p0-4,p05 for qei.
const InputPin<PortNumber(0), BitNumber(4)> primePhase(BusLatch);
const InputPin<0, 5> otherPhase(BusLatch);

Irq<4> qeiPrimeIrq;

// prime phase interrupt
HandleInterrupt(4){ // interrupt number and bit number coincidentally the same.
  pos.step<true>(primePhase==otherPhase);
}

/////////////{
#include "fifo.h"
static FifoBuffer<33> outgoing;
static FifoBuffer<63> incoming;

/** called by isr on an input event.
 * negative values of @param are notifications of line errors, -1 for interrupts disabled */
bool uartReceiver(int indata){
  if((incoming=u8(indata))){
    return true;
  } else {
    wtf(24);
    return false;
  }
}

/** called by isr when transmission becomes possible.
 *  @returns either an 8 bit unsigned character, or -1 to disable transmission events*/
int uartSender(){
  return outgoing;//negative for fifo empty
}

const char testMessage[]="Jello Whirled\r\n";

#include "uart.h"
Uart theUart(&uartReceiver,&uartSender);

HandleInterrupt(uartIrq){
  theUart.isr();
}

P1343devkit kit;
//CyclicTimer ledToggle;

int main(void){
  theUart.setBaud(115200,ExpectedClock);
  theUart.reception(true);

  outgoing.stuff(testMessage,sizeof(testMessage));
  theUart.beTransmitting();

  theUart.irq(true);//most likely this is superfluous

  // interrupt defaults to edge sensitive
  qeiPrimeIrq.enable();

  startPeriodicTimer(1000);//shoot for millisecond resolution
  ledToggle.retrigger();//seconds
  while(1) {
    MNE(WFE);//WFE is more inclusive than WFI, events don't call an isr but do wakeup the core.
    if(ledToggle){
      kit.led3=!kit.led3;
    }
  }
  return 0;//avert useless warning
} // main

#ifdef HOST_SIM // cross compilation fakeouts
//// vendore specific code must provide a clock source, architecture varies greatly across vendors.
//unsigned clockRate(unsigned which){
//  return 12000000;
//}
#else //target build

#endif
<commit_msg>uart settings generator wworking, not yet embedded<commit_after>/* dro project
 * this attempt is with lpc1343, using Olimex P1343 dev kit (8 LED's :)
 */
#include "quadraturecounter.h"
QuadratureCounter pos;//as in 'position'

#include "lpc13xx.h"
#include "gpio.h"
#include "nvic.h"

//shared ~millisecond services:
#include "systick.h"
using namespace SystemTimer;
#include "polledtimer.h"
#include "tableofpointers.h"

CyclicTimer ledToggle(750);//todo: clearer timebase
RegisterTimer(ledToggle);

#include "core_cmInstr.h"  //wfe OR wfi
#include "cruntime.h"

#include "p1343_board.h" //P1343devkit //for led's
#include "wtf.h"
using namespace LPC;

//should inherit from a board description header
const unsigned ExpectedClock=12000000;

// using p0-4,p05 for qei.
const InputPin<PortNumber(0), BitNumber(4)> primePhase(BusLatch);
const InputPin<0, 5> otherPhase(BusLatch);

Irq<4> qeiPrimeIrq;

// prime phase interrupt
HandleInterrupt(4){ // interrupt number and bit number coincidentally the same.
  pos.step<true>(primePhase==otherPhase);
}

/////////////{
#include "fifo.h"
static FifoBuffer<33> outgoing;
static FifoBuffer<63> incoming;

/** called by isr on an input event.
 * negative values of @param are notifications of line errors, -1 for interrupts disabled */
bool uartReceiver(int indata){
  if((incoming=u8(indata))){
    return true;
  } else {
    wtf(24);
    return false;
  }
}

/** called by isr when transmission becomes possible.
 *  @returns either an 8 bit unsigned character, or -1 to disable transmission events*/
int uartSender(){
  return outgoing;//negative for fifo empty
}

const char testMessage[]="Jello Whirled\r\n";

#include "uart.h"
Uart theUart(&uartReceiver,&uartSender);

HandleInterrupt(uartIrq){
  theUart.isr();
}

P1343devkit kit;
//CyclicTimer ledToggle;

int main(void){
  unsigned actualBaud=theUart.setBaudPieces(6,12,1,ExpectedClock);//externally generated

  theUart.reception(true);

  outgoing.stuff(testMessage,sizeof(testMessage));
  theUart.beTransmitting();

  theUart.irq(true);//most likely this is superfluous

  // interrupt defaults to edge sensitive
  qeiPrimeIrq.enable();

  startPeriodicTimer(1000);//shoot for millisecond resolution
  ledToggle.retrigger();//seconds
  while(1) {
    MNE(WFE);//WFE is more inclusive than WFI, events don't call an isr but do wakeup the core.
    if(ledToggle){
      kit.led3=!kit.led3;
    }
  }
  return 0;//avert useless warning
} // main

#ifdef HOST_SIM // cross compilation fakeouts
//// vendore specific code must provide a clock source, architecture varies greatly across vendors.
//unsigned clockRate(unsigned which){
//  return 12000000;
//}
#else //target build

#endif
<|endoftext|>