ui: snippet sizes

* added SnippetMerger class that conducts the merging and snapping of TokenLocations to create snippets.
* added parameters for snippet snapping and merging to ApplicationSettings.
* added forEachStartTokenLocation() and forEachEndTokenLocation() to TokenLocationLine and TokenLocationFile.
* added < and > operators to TokenLocation that compare the location part (not the id).
This commit is contained in:
malte_langkabel
2015-05-04 15:00:18 +02:00
parent 4ec3dfd372
commit fd73abde64
19 changed files with 345 additions and 35 deletions
@@ -35,6 +35,10 @@
<LinkColor><!-- COLOR: color of clickable elements in the source view --></LinkColor>
<ScopeColor><!-- COLOR: color of clickable scopes in the source view --></ScopeColor>
<ActiveLinkColor><!-- COLOR: color of active elements or scopes in the source view --></ActiveLinkColor>
<snippet>
<snap_range><!-- INTEGER: max amount of lines that the current snippet will be extended to snap to scope start/end --></snap_range>
<expand_range><!-- INTEGER: amount of lines that the snippet range (not snapped) will be extended --></expand_range>
</snippet>
</code>
<colors>
+3
View File
@@ -35,6 +35,9 @@ add_files(
add_files(
LIB_FILES
component/controller/helper/SnippetMerger.cpp
component/controller/helper/SnippetMerger.h
component/controller/CodeController.cpp
component/controller/CodeController.h
component/controller/Controller.cpp
+47 -34
View File
@@ -4,6 +4,7 @@
#include "data/location/TokenLocation.h"
#include "data/location/TokenLocationCollection.h"
#include "data/location/TokenLocationFile.h"
#include "settings/ApplicationSettings.h"
#include "utility/text/TextAccess.h"
CodeController::CodeController(StorageAccess* storageAccess)
@@ -29,12 +30,13 @@ void CodeController::handleMessage(MessageActivateTokenLocation* message)
void CodeController::handleMessage(MessageActivateTokens* message)
{
std::vector<Id> activeTokenIds = message->tokenIds;
Id declarationId = 0;
Id declarationId = 0; // 0 means that no token is found.
if (activeTokenIds.size() == 1)
{
activeTokenIds = m_storageAccess->getActiveTokenIdsForId(activeTokenIds[0], &declarationId);
}
// TODO: what about declarationId if more than 1 token is active? FIX THIS!
CodeView* view = getView();
view->setActiveTokenIds(activeTokenIds);
@@ -144,24 +146,37 @@ std::vector<CodeView::CodeSnippetParams> CodeController::getSnippetsForFile(cons
{
std::shared_ptr<TextAccess> textAccess = TextAccess::createFromFile(file->getFilePath().str());
std::vector<std::pair<uint, uint>> ranges;
std::deque<SnippetMerger::Range> ranges;
if (file->isWholeCopy)
{
ranges.push_back(std::make_pair(1, textAccess->getLineCount()));
ranges.push_back(SnippetMerger::Range(
SnippetMerger::Border(1, true),
SnippetMerger::Border(textAccess->getLineCount(), true)
));
}
else
{
ranges = getSnippetRangesForFile(file);
SnippetMerger fileScopedMerger(1, textAccess->getLineCount());
std::map<int, std::shared_ptr<SnippetMerger>> mergers;
file->forEachStartTokenLocation(
[&](TokenLocation* location)
{
buildMergerHierarchy(location, fileScopedMerger, mergers);
}
);
ranges = fileScopedMerger.merge();
}
const int snippetExpandRange = ApplicationSettings::getInstance()->getCodeSnippetExpandRange();
std::vector<CodeView::CodeSnippetParams> snippets;
for (const std::pair<uint, uint>& range: ranges)
for (const SnippetMerger::Range& range: ranges)
{
CodeView::CodeSnippetParams params;
params.locationFile = *file;
params.startLineNumber = std::max<int>(1, range.first - s_lineRadius);
params.endLineNumber = std::min<int>(textAccess->getLineCount(), range.second + s_lineRadius);
params.startLineNumber = std::max<int>(1, range.start.row - (range.start.strong ? 0 : snippetExpandRange));
params.endLineNumber = std::min<int>(textAccess->getLineCount(), range.end.row + (range.end.strong ? 0 : snippetExpandRange));
for (const std::string& line: textAccess->getLines(params.startLineNumber, params.endLineNumber))
{
@@ -174,40 +189,38 @@ std::vector<CodeView::CodeSnippetParams> CodeController::getSnippetsForFile(cons
return snippets;
}
std::vector<std::pair<uint, uint>> CodeController::getSnippetRangesForFile(const TokenLocationFile* file) const
std::shared_ptr<SnippetMerger> CodeController::buildMergerHierarchy(
TokenLocation* location, SnippetMerger& fileScopedMerger, std::map<int, std::shared_ptr<SnippetMerger>>& mergers) const
{
std::vector<std::pair<uint, uint>> ranges;
uint start = 0;
uint end = 0;
const TokenLocation* currentLocation = location;
std::shared_ptr<SnippetMerger> currentMerger = std::make_shared<SnippetMerger>(
currentLocation->getStartTokenLocation()->getLineNumber(),
currentLocation->getEndTokenLocation()->getLineNumber()
);
file->forEachTokenLocation(
[&](TokenLocation* location) -> void
std::shared_ptr<TokenLocationFile> locationFile = m_storageAccess->getTokenLocationOfParentScope(currentLocation);
if (locationFile->getTokenLocationLineCount() == 0)
{
fileScopedMerger.addChild(currentMerger);
return currentMerger;
}
std::shared_ptr<SnippetMerger> nextMerger;
locationFile->forEachStartTokenLocation( // contains just 1 start location
[&](TokenLocation* scopeLocation)
{
uint lineNumber = location->getLineNumber();
if (location->isStartTokenLocation())
std::map<int, std::shared_ptr<SnippetMerger>>::iterator it = mergers.find(scopeLocation->getId());
if (it == mergers.end())
{
if (start && end && lineNumber > end + 2 * s_lineRadius + 1)
{
ranges.push_back(std::make_pair(uint(start), uint(end)));
start = end = 0;
}
if (!start)
{
start = lineNumber;
}
lineNumber = location->getEndTokenLocation()->getLineNumber();
nextMerger = buildMergerHierarchy(scopeLocation, fileScopedMerger, mergers);
mergers[scopeLocation->getId()] = nextMerger;
}
if (lineNumber > end)
else
{
end = lineNumber;
nextMerger = it->second;
}
}
);
ranges.push_back(std::make_pair(uint(start), uint(end)));
return ranges;
nextMerger->addChild(currentMerger);
return currentMerger;
}
@@ -2,6 +2,7 @@
#define CODE_CONTROLLER_H
#include <string>
#include <map>
#include "component/controller/Controller.h"
#include "component/view/CodeView.h"
@@ -13,6 +14,10 @@
#include "utility/messaging/type/MessageShowFile.h"
#include "utility/types.h"
#include "component/controller/helper/SnippetMerger.h"
class StorageAccess;
class TokenLocationFile;
@@ -42,7 +47,8 @@ private:
std::vector<CodeView::CodeSnippetParams> getSnippetsForActiveTokenIds(
const std::vector<Id>& ids, Id declarationId) const;
std::vector<CodeView::CodeSnippetParams> getSnippetsForFile(const TokenLocationFile* file) const;
std::vector<std::pair<uint, uint>> getSnippetRangesForFile(const TokenLocationFile* file) const;
std::shared_ptr<SnippetMerger> buildMergerHierarchy(
TokenLocation* location, SnippetMerger& fileScopedMerger, std::map<int, std::shared_ptr<SnippetMerger>>& mergers) const;
StorageAccess* m_storageAccess;
};
@@ -0,0 +1,74 @@
#include "component/controller/helper/SnippetMerger.h"
#include <algorithm>
#include "settings/ApplicationSettings.h"
SnippetMerger::SnippetMerger(int startRow, int endRow)
: m_start(startRow)
, m_end(endRow)
{
}
void SnippetMerger::addChild(std::shared_ptr<SnippetMerger> child)
{
m_children.push_back(child);
}
std::deque<SnippetMerger::Range> SnippetMerger::merge() const
{
std::deque<Range> merged;
if (m_children.size() == 0)
{
merged.push_back(Range(Border(m_start, false), Border(m_end, false)));
}
else
{
for (size_t i = 0; i < m_children.size(); i++)
{
std::deque<Range> mergedFromChild = m_children[i]->merge();
for (size_t j = 0; j < mergedFromChild.size(); j++)
{
merged.push_back(mergedFromChild[j]);
}
}
std::sort(merged.begin(), merged.end(),
[](const Range& a, const Range& b)
{
return a.start.row < b.start.row;
}
);
// merge children
const int snippetExpandRange = ApplicationSettings::getInstance()->getCodeSnippetExpandRange();
const int snippetMergeRange = 2 * snippetExpandRange + 1; // +1 since snippets that end/start with consequtive
// lines should be merged as well.
for (size_t i = 0; i < merged.size() - 1; i++)
{
const Range first = merged[i];
const Range second = merged[i + 1];
if (first.end.row + snippetMergeRange >= second.start.row)
{
merged.erase(merged.begin() + i, merged.begin() + i + 2);
merged.insert(merged.begin() + i, Range(
first.start.row < second.start.row ? first.start : second.start,
first.end.row > second.end.row ? first.end : second.end
));
i--;
}
}
// snap to own borders
const int snippetSnapRange = ApplicationSettings::getInstance()->getCodeSnippetSnapRange();
if (m_start + snippetSnapRange >= merged.front().start.row)
{
merged.front().start.row = m_start;
merged.front().start.strong = true;
}
if (m_end - snippetSnapRange <= merged.back().end.row)
{
merged.back().end.row = m_end;
merged.back().end.strong = true;
}
}
return merged;
}
@@ -0,0 +1,34 @@
#ifndef SNIPPET_MERGER_H
#define SNIPPET_MERGER_H
#include <deque>
#include <memory>
#include <vector>
class SnippetMerger
{
public:
struct Border
{
Border(int row, bool strong): row(row), strong(strong) {}
int row;
bool strong;
};
struct Range
{
Range (Border start, Border end): start(start), end(end) {}
Border start;
Border end;
};
SnippetMerger(int startRow, int endRow);
void addChild(std::shared_ptr<SnippetMerger> child);
std::deque<Range> merge() const;
private:
const int m_start;
const int m_end;
std::vector<std::shared_ptr<SnippetMerger>> m_children;
};
#endif // SNIPPET_MERGER_H
+42
View File
@@ -1055,6 +1055,48 @@ TokenLocationCollection Storage::getErrorTokenLocations(std::vector<std::string>
return m_errorLocationCollection;
}
std::shared_ptr<TokenLocationFile> Storage::getTokenLocationOfParentScope(const TokenLocation* child) const
{
const TokenLocation* parent = child;
const FilePath filePath = child->getFilePath();
const TokenLocationFile* locationFile = m_locationCollection.findTokenLocationFileByPath(child->getFilePath());
locationFile->forEachTokenLocation(
[&](TokenLocation* tokenLocation) -> void
{
if (tokenLocation->isStartTokenLocation())
{
TokenLocation::LocationType lt = tokenLocation->getType();
int sln = tokenLocation->getLineNumber();
int eln = tokenLocation->getEndTokenLocation()->getLineNumber();
if (tokenLocation->getType() == TokenLocation::LOCATION_SCOPE &&
tokenLocation->isStartTokenLocation() &&
(*tokenLocation) < *(child->getStartTokenLocation()) &&
(*tokenLocation->getEndTokenLocation()) > *(child->getEndTokenLocation()))
{
if (parent == child)
{
parent = tokenLocation;
}
else
{
if ((*tokenLocation) > *parent) // since tokenLocation is a start location the > location indiceates the scope that is closer to the child.
{
parent = tokenLocation;
}
}
}
}
}
);
std::shared_ptr<TokenLocationFile> file = std::make_shared<TokenLocationFile>(filePath);
if (parent != child)
{
file->addTokenLocationAsPlainCopy(parent);
file->addTokenLocationAsPlainCopy(parent->getOtherTokenLocation());
}
return file;
}
const Graph& Storage::getGraph() const
{
return m_graph;
+2
View File
@@ -126,6 +126,8 @@ public:
virtual TokenLocationCollection getErrorTokenLocations(std::vector<std::string>* errorMessages) const;
virtual std::shared_ptr<TokenLocationFile> getTokenLocationOfParentScope(const TokenLocation* child) const;
protected:
const Graph& getGraph() const;
const TokenLocationCollection& getTokenLocationCollection() const;
+2
View File
@@ -11,6 +11,7 @@
#include "data/search/SearchMatch.h"
class Graph;
class TokenLocation;
class TokenLocationCollection;
class TokenLocationFile;
@@ -38,6 +39,7 @@ public:
const std::string& filePath, uint firstLineNumber, uint lastLineNumber) const = 0;
virtual TokenLocationCollection getErrorTokenLocations(std::vector<std::string>* errorMessages) const = 0;
virtual std::shared_ptr<TokenLocationFile> getTokenLocationOfParentScope(const TokenLocation* child) const = 0;
};
#endif // STORAGE_ACCESS_H
@@ -153,3 +153,13 @@ TokenLocationCollection StorageAccessProxy::getErrorTokenLocations(std::vector<s
return TokenLocationCollection();
}
std::shared_ptr<TokenLocationFile> StorageAccessProxy::getTokenLocationOfParentScope(const TokenLocation* child) const
{
if (hasSubject())
{
return m_subject->getTokenLocationOfParentScope(child);
}
return std::make_shared<TokenLocationFile>("");
}
+2
View File
@@ -34,6 +34,8 @@ public:
virtual TokenLocationCollection getErrorTokenLocations(std::vector<std::string>* errorMessages) const;
virtual std::shared_ptr<TokenLocationFile> getTokenLocationOfParentScope(const TokenLocation* child) const;
private:
StorageAccess* m_subject;
};
+44
View File
@@ -39,6 +39,26 @@ TokenLocation::~TokenLocation()
{
}
bool TokenLocation::operator<(const TokenLocation& rhs) const
{
return (
getLineNumber() < rhs.getLineNumber() || (
getLineNumber() == rhs.getLineNumber() &&
getColumnNumber() < rhs.getColumnNumber()
)
);
}
bool TokenLocation::operator>(const TokenLocation& rhs) const
{
return (
getLineNumber() > rhs.getLineNumber() || (
getLineNumber() == rhs.getLineNumber() &&
getColumnNumber() > rhs.getColumnNumber()
)
);
}
Id TokenLocation::getId() const
{
return m_id;
@@ -123,6 +143,30 @@ TokenLocation* TokenLocation::getEndTokenLocation()
}
}
const TokenLocation* TokenLocation::getStartTokenLocation() const
{
if (m_isStart)
{
return this;
}
else
{
return m_other;
}
}
const TokenLocation* TokenLocation::getEndTokenLocation() const
{
if (!m_isStart)
{
return this;
}
else
{
return m_other;
}
}
bool TokenLocation::isStartTokenLocation() const
{
return m_isStart;
+6
View File
@@ -26,6 +26,9 @@ public:
TokenLocation(const TokenLocation& other, TokenLocationLine* line);
~TokenLocation();
bool operator<(const TokenLocation& rhs) const;
bool operator>(const TokenLocation& rhs) const;
Id getId() const;
Id getTokenId() const;
@@ -45,6 +48,9 @@ public:
TokenLocation* getStartTokenLocation();
TokenLocation* getEndTokenLocation();
const TokenLocation* getStartTokenLocation() const;
const TokenLocation* getEndTokenLocation() const;
bool isStartTokenLocation() const;
bool isEndTokenLocation() const;
@@ -89,6 +89,22 @@ void TokenLocationFile::forEachTokenLocation(std::function<void(TokenLocation*)>
}
}
void TokenLocationFile::forEachStartTokenLocation(std::function<void(TokenLocation*)> func) const
{
for (const TokenLocationLinePairType& line : m_lines)
{
line.second->forEachStartTokenLocation(func);
}
}
void TokenLocationFile::forEachEndTokenLocation(std::function<void(TokenLocation*)> func) const
{
for (const TokenLocationLinePairType& line : m_lines)
{
line.second->forEachEndTokenLocation(func);
}
}
TokenLocation* TokenLocationFile::addTokenLocationAsPlainCopy(const TokenLocation* location)
{
unsigned int lineNumber = location->getTokenLocationLine()->getLineNumber();
@@ -37,6 +37,8 @@ public:
void forEachTokenLocationLine(std::function<void(TokenLocationLine*)> func) const;
void forEachTokenLocation(std::function<void(TokenLocation*)> func) const;
void forEachStartTokenLocation(std::function<void(TokenLocation*)> func) const;
void forEachEndTokenLocation(std::function<void(TokenLocation*)> func) const;
TokenLocation* addTokenLocationAsPlainCopy(const TokenLocation* location);
@@ -91,6 +91,28 @@ void TokenLocationLine::forEachTokenLocation(std::function<void(TokenLocation*)>
}
}
void TokenLocationLine::forEachStartTokenLocation(std::function<void(TokenLocation*)> func) const
{
for (const TokenLocationPairType& location : m_locations)
{
if (location.second->isStartTokenLocation())
{
func(location.second.get());
}
}
}
void TokenLocationLine::forEachEndTokenLocation(std::function<void(TokenLocation*)> func) const
{
for (const TokenLocationPairType& location : m_locations)
{
if (location.second->isEndTokenLocation())
{
func(location.second.get());
}
}
}
TokenLocation* TokenLocationLine::addTokenLocationAsPlainCopy(const TokenLocation* location)
{
std::shared_ptr<TokenLocation> locationPtr = std::make_shared<TokenLocation>(*location, this);
@@ -37,6 +37,8 @@ public:
TokenLocation* getTokenLocationById(Id id) const;
void forEachTokenLocation(std::function<void(TokenLocation*)> func) const;
void forEachStartTokenLocation(std::function<void(TokenLocation*)> func) const;
void forEachEndTokenLocation(std::function<void(TokenLocation*)> func) const;
TokenLocation* addTokenLocationAsPlainCopy(const TokenLocation* location);
+20
View File
@@ -86,6 +86,26 @@ void ApplicationSettings::setCodeActiveLinkColor(Colori color)
setValue<std::string>("code/ActiveLinkColor", color.toString());
}
int ApplicationSettings::getCodeSnippetSnapRange() const
{
return getValue<int>("code/snippet/snap_range", 4);
}
void ApplicationSettings::setCodeSnippetSnapRange(int range)
{
setValue<int>("code/snippet/snap_range", range);
}
int ApplicationSettings::getCodeSnippetExpandRange() const
{
return getValue<int>("code/snippet/expand_range", 2);
}
void ApplicationSettings::setCodeSnippetExpandRange(int range)
{
setValue<int>("code/snippet/expand_range", range);
}
std::string ApplicationSettings::getNodeTypeColor(Node::NodeType type, const std::string& state) const
{
std::string path = "colors/" + Node::getTypeString(type) + "/" + state;
+6
View File
@@ -38,6 +38,12 @@ public:
Colori getCodeActiveLinkColor() const;
void setCodeActiveLinkColor(Colori color);
int getCodeSnippetSnapRange() const;
void setCodeSnippetSnapRange(int range);
int getCodeSnippetExpandRange() const;
void setCodeSnippetExpandRange(int range);
// colors
std::string getNodeTypeColor(Node::NodeType type, const std::string& state = "normal") const;
void setNodeTypeColor(Node::NodeType type, const std::string& color, const std::string& state = "normal");