1. 程式人生 > >生產力:編寫屬於你自己的日誌分析器(3)

生產力:編寫屬於你自己的日誌分析器(3)

這一節講解如何擴充套件Scintilla,用來在右側滾動條區域增加各種標記(不同形狀和顏色)。這種在滾動條上顯示標記的做法在一些主流編輯器上很流行,比如XCode用紅色標記編譯error,用黃色標記編譯warning(參見下圖右側滾動條區域):


Scintilla本並不支援客製化滾動條。原生支援的margin顯示在視窗左側,跟隨視窗內容一起滾動,並不能提供整個文件的概覽。

幸運的是,Scintilla是開源的,我們加少許程式碼就可以支援這個功能。

1. 在Scintilla.h中增加訊息型別

#defineSCI_BARLINEADD2800
#defineSCI_BARLINEDELETE
2801
#defineSCI_BARLINECLEAR2802
這3個訊息分別是:增加某行bar line,刪除某行bar line,清楚某類bar line

2. 編輯Editor.cxx

在函式Editor::WndProc裡增加SCI_BARLINEADDSCI_BARLINEDELETE,以及SCI_BARLINECLEAR的處理函式:

caseSCI_BARLINEADD:{//wParam:group|line,lParam:color.AddedbyZhenyong
pdoc->AddBarLine(static_cast<unsignedint>(wParam),static_cast
<int>(lParam));
break;
}
caseSCI_BARLINEDELETE:{//wParam:group|line.AddedbyZhenyong
pdoc->DeleteBarLine(static_cast<unsignedint>(wParam));
break;
}
caseSCI_BARLINECLEAR:{//wParam:group
pdoc->ClearBarLine(static_cast<unsignedint>(wParam));
break;
}

這裡簡單地交由class Document去處理。

3. 編輯Document

標頭檔案:Document.h

增加3個函式宣告:

voidAddBarLine(unsignedintgroupAndLine,unsignedintcolor);
voidDeleteBarLine(unsignedintgroupAndLine);
voidClearBarLine(unsignedintgroup);
儲存bar line資料:
public:
ScrollBarLine*getBarLine(){returnbarLine;}
private:
ScrollBarLine*barLine;

實現檔案:Document.cxx
Document::Document(){
    ...
barLine=newScrollBarLine();
    ...
}

//shapeGroupAndLine:4:8:20
voidDocument::AddBarLine(unsignedintshapeGroupAndLine,unsignedintcolor){
unsignedintshape=shapeGroupAndLine>>28;
unsignedintgroup=shapeGroupAndLine<<4>>24;
unsignedintline=shapeGroupAndLine<<12>>12;
if(line<=(unsignedint)LinesTotal()){
getBarLine()->InsertLine(group,line,shape,color);
}
}
voidDocument::DeleteBarLine(unsignedintgroupAndLine){
unsignedintgroup=groupAndLine>>16;
unsignedintline=groupAndLine&0xFFFF;
if(line<=(unsignedint)LinesTotal()){
getBarLine()->RemoveLine(group,line);
}
}
voidDocument::ClearBarLine(unsignedintgroup){
getBarLine()->ClearGroup(group);
}

Document裡用到了ScrollBarLine來儲存bar line資訊。定義這個型別在PerLine.h中。

4. 編輯PerLine.h

//Paintlinesinverticalscrollbararea
//AddedbyZhenyong(2017/06/24)
classScrollBarLine{
public:
structbarParam{
unsignedintline;//whichline
unsignedintcolor;
unsignedintshape;//1:line;2:triangledown;3:triangleup
};
std::list<barParam>&getBarLineList(intgroup){
if(group<0)
group=0;
elseif(group>9)
group=9;
returnbarLineList[group];
}
intInsertLine(unsignedintgroup,unsignedintline,unsignedintshape,unsignedintcolor);
intRemoveLine(unsignedintgroup,unsignedintline);
voidClearGroup(unsignedintgroup);
private:
std::list<barParam>barLineList[10];
};
這裡設定了10個group。用group的好處是可以把不同的group的標記繪製在不同的列上,增加標記的辨識度。

每個bar有位置(line number),顏色,形狀屬性。

相應的,實現檔案PerLine.cxx:

intScrollBarLine::InsertLine(unsignedintgroup,unsignedintline,unsignedintshape,unsignedintcolor)
{
if(group>9)
return-1;
std::list<barParam>&list=getBarLineList(group);
structbarParamparam;
param.line=line;
param.color=color;
param.shape=shape;
list.push_back(param);
return0;
}
intScrollBarLine::RemoveLine(unsignedintgroup,unsignedintline)
{
if(group>9)
return-1;
std::list<barParam>&list=getBarLineList(group);
std::list<barParam>::iteratorit;
for(it=list.begin();it!=list.end();it++){
structbarParam&param=*it;
if((unsignedint)param.line==line){
list.erase(it);
return0;
}
}
return-1;
}
voidScrollBarLine::ClearGroup(unsignedintgroup)
{
if(group>9)
return;
std::list<barParam>&list=getBarLineList(group);
list.clear();
}

5. 繪製程式碼

開啟Editor.cxx, 找到函式ScrollBarLine

voidEditor::Paint(Surface*surfaceWindow,PRectanglercArea){
    ...
//hackbyZhenyong:drawrowindications
inttotalLines=pdoc->LinesTotal();
if(totalLines>0){
floath1=LocationFromPosition(PositionFromLineX(1,0)).y;
floath2=LocationFromPosition(PositionFromLineX(totalLines,0)).y;
floattotalHeight=h2-h1;
XYPOSITIONx1;
XYPOSITIONx2=rcClient.right-2;
x1=x2-12;
for(intgroup=0;group<10;group++){
std::list<ScrollBarLine::barParam>&barLineList=pdoc->getBarLine()->getBarLineList(group);
std::list<ScrollBarLine::barParam>::iteratorit;
if(barLineList.size()==0)
continue;
for(it=barLineList.begin();it!=barLineList.end();it++){
ScrollBarLine::barParam&param=*it;
if(it==barLineList.begin()){
surfaceWindow->PenColour(ColourDesired(param.color));
}
XYPOSITIONy=LocationFromPosition(PositionFromLineX(param.line,0)).y-h1;
//XYPOSITIONy=param.line*rcClient.Height()/totalLines;//TODO:gettruelineposition
if((int)totalHeight>(int)rcClient.Height()&&(int)rcClient.Height()>0){
y=y/totalHeight*rcClient.Height();
}
if((int)y==0)
y=1.0;
elseif((int)y==(int)rcClient.Height())
y-=1.0;
if(param.shape==1){
surfaceWindow->MoveTo(x1,y);
surfaceWindow->LineTo(x2,y);
}
else{
Pointpts[3];
if(param.shape==2){
constintw=12;
pts[0].x=x1-w;
pts[0].y=y;
pts[1].x=x1;
pts[1].y=y;
pts[2].x=x1-w/2;
pts[2].y=y+0.3*w;
}
elseif(param.shape==3){
constintw=12;
pts[0].x=x1-w/2;
pts[0].y=y;
pts[1].x=x1-w;
pts[1].y=y+0.3*w;
pts[2].x=x1;
pts[2].y=y+0.3*w;
}
surfaceWindow->Polygon(pts,3,param.color,param.color);
}
}
}
}
NotifyPainted();
}

至此Scintilla的增強完成了。下一節講解編寫app來實現一個強大的閱讀器。