CE Editor Sources.cpp 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. /******************************************************************************/
  2. #include "stdafx.h"
  3. namespace EE{
  4. namespace Edit{
  5. /******************************************************************************/
  6. void CodeEditor::cur(Source *cur)
  7. {
  8. if(T._cur!=cur && parent)
  9. {
  10. if(T._cur)*parent-=*T._cur; // hide old
  11. if(T._cur=cur) // set and show new
  12. {
  13. *parent+=*cur;
  14. cur->moveToBottom().moveAbove(menu); // move to bottom below 'browse_mode' buttons, but above 'menu' so alt is processed properly (Menu Alt detection relies on 'Kb.k' detection, which can be eaten by this gui object, so make sure 'menu' is processed first)
  15. cur->prepareForDraw();
  16. cur->activate();
  17. if(!cur->opened)
  18. {
  19. cur->opened=true;
  20. //sources.moveToEnd(curI()); this won't work with 'find previous/next' and can make engine headers be between custom sources
  21. }
  22. if(cur->used())init(); // if activated a used source then make sure that Code Editor is initialized (do this after operating on 'cur' in case 'init' will somehow change/delete it)
  23. }
  24. b_close.visible(T._cur!=null && menu.visible()); // close button is visible on top of menu (so display only if that's visible too)
  25. cei().sourceChanged(true);
  26. }
  27. }
  28. /******************************************************************************/
  29. Source& CodeEditor::New()
  30. {
  31. Source &src=sources.New();
  32. cur(&src);
  33. return src;
  34. }
  35. /******************************************************************************/
  36. void CodeEditor::sourceRemoved(Source &src)
  37. {
  38. REPA(curpos)
  39. {
  40. if(curpos[i].source==&src){curpos.remove(i, true); if(i<curposi)curposi--;}
  41. }
  42. // adjust symbols
  43. REPA(Symbols)
  44. {
  45. Symbol &symbol=Symbols.lockedData(i);
  46. if(symbol.source==&src)symbol.source=null;
  47. }
  48. // exclude from opened
  49. src.opened=false;
  50. // make sure it's not current
  51. if(cur()==&src)nextFile();
  52. }
  53. /******************************************************************************/
  54. void CodeEditor::closeDo()
  55. {
  56. if(Source *s=cur())
  57. {
  58. s->opened=false; // close
  59. prevFile(); // activate previous opened source
  60. if(s->used())s->reload();else sources.removeData(s, true); // if 's' is used in the project then reload to maintain last saved position (in case there were some changes applied, but the user decided not to save them), if not then remove from 'sources'
  61. cei().sourceChanged();
  62. }
  63. }
  64. void CodeEditor::closeAll()
  65. {
  66. for(; cur(); )closeDo();
  67. removeUselessSources();
  68. }
  69. /******************************************************************************/
  70. static Bool SaveSource(Edit::SaveChanges::Elm &elm) {REPA(CE.sources)if(elm.user==&CE.sources[i])return CE.sources[i].overwrite(); return true;}
  71. static void CloseSource(Edit::SaveChanges::Elm &elm) {if(CE.cur() && elm.user==CE.cur())CE.closeDo();}
  72. void CodeEditor::close()
  73. {
  74. if(cur())
  75. {
  76. if(cur()->modified())
  77. {
  78. save_changes.set(Edit::SaveChanges::Elm().set(cur()->loc.file_name, S+"Source - \""+cur()->loc.asText()+'"', cur()->loc.id, cur()).save(SaveSource).close(CloseSource));
  79. }else
  80. {
  81. closeDo();
  82. }
  83. }
  84. }
  85. void CodeEditor::saveChanges()
  86. {
  87. REPA(sources)
  88. {
  89. Source &src=sources[i];
  90. if(src.modified())src.overwrite();
  91. }
  92. }
  93. void CodeEditor::saveChanges(Memc<Edit::SaveChanges::Elm> &elms)
  94. {
  95. REPA(sources)
  96. {
  97. Source &src=sources[i];
  98. if(src.modified())elms.New().set(src.loc.file_name, S+"Source - \""+src.loc.asText()+'"', src.loc.id, &src).save(SaveSource);
  99. }
  100. }
  101. /******************************************************************************/
  102. void CodeEditor::removeUselessSources()
  103. {
  104. REPA(sources){Source &src=sources[i]; if(!src.opened && !src.used())sources.removeValid(i, true);}
  105. }
  106. /******************************************************************************/
  107. CodeEditor::CurPos CodeEditor::curPos() {if(Source *source=cur())return CurPos(source->cur.x, InRange(source->cur.y, source->lines) ? source->lines[source->cur.y].id : UIDZero, source); return CurPos(0, UIDZero, null);}
  108. /******************************************************************************/
  109. void CodeEditor::markCurPos()
  110. {
  111. if(Source *source=cur())
  112. {
  113. CurPos cp=curPos();
  114. if(InRange(curposi-1, curpos))
  115. {
  116. CurPos &prev=curpos[curposi-1];
  117. if(prev==cp)return;
  118. if(prev.source==cp.source && prev.line==cp.line && Abs(prev.col-cp.col)<=3){prev.col=cp.col; return;}
  119. }
  120. if(InRange(curposi, curpos))
  121. {
  122. CurPos &next=curpos[curposi];
  123. if(next==cp){curposi++; return;}
  124. }
  125. curpos.NewAt(curposi++)=cp;
  126. if(curposi >128){curpos.remove(0, true); curposi--;}else
  127. if(curpos.elms()-curposi>128){curpos.removeLast( ); }
  128. }
  129. }
  130. /******************************************************************************/
  131. void CodeEditor::prevCurPos() {if(InRange(curposi-1, curpos)){markCurPos(); CurPos cp=curPos(); for(; InRange(curposi-1, curpos); ){jumpTo(curpos[--curposi ]); if(cp!=curPos())break;}}}
  132. void CodeEditor::nextCurPos() {if(InRange(curposi , curpos)){markCurPos(); CurPos cp=curPos(); for(; InRange(curposi , curpos); ){jumpTo(curpos[ curposi++]); if(cp!=curPos())break;}}}
  133. /******************************************************************************/
  134. void CodeEditor::prevIssue() {CurPos cp=curPos(); FREP(build_list.visibleElms()){Int v=Mod( build_list.highlight_line -i, build_list.visibleElms()); if(BuildResult *br=build_list.visToData(v))if(br->jumpTo() && (cp!=curPos() || build_list.highlight_line<0)){build_list.highlight_line=v; build_list.highlight_time=Time.appTime(); build_list.scrollTo(v, false, 0.5f); break;}}}
  135. void CodeEditor::nextIssue() {CurPos cp=curPos(); FREP(build_list.visibleElms()){Int v=Mod(Max(0, build_list.highlight_line)+i, build_list.visibleElms()); if(BuildResult *br=build_list.visToData(v))if(br->jumpTo() && (cp!=curPos() || build_list.highlight_line<0)){build_list.highlight_line=v; build_list.highlight_time=Time.appTime(); build_list.scrollTo(v, false, 0.5f); break;}}}
  136. /******************************************************************************/
  137. void CodeEditor::jumpTo(CurPos &cp)
  138. {
  139. Bool immediate=(cur()!=cp.source);
  140. cur(cp.source);
  141. cp.source->sel=-1;
  142. cp.source->cur= 0;
  143. Int l=cp.source->findLine(cp.line); if(l>=0)cp.source->cur.set(cp.col, l);
  144. if(!view_mode())cp.source->makeCurVisible(true, immediate);else
  145. if( l>=0 )cp.source->highlight (l , immediate);
  146. }
  147. /******************************************************************************/
  148. void CodeEditor::jumpTo(Source *source, Int line)
  149. {
  150. if(source)
  151. {
  152. markCurPos();
  153. Source *old=cur();
  154. cur(source);
  155. source->sel=-1;
  156. source->cur= 0;
  157. source->highlight(line, old!=cur());
  158. }
  159. }
  160. /******************************************************************************/
  161. void CodeEditor::jumpTo(Macro *macro)
  162. {
  163. if(macro)jumpTo(macro->source, macro->line);
  164. }
  165. /******************************************************************************/
  166. void CodeEditor::jumpTo(Symbol *symbol)
  167. {
  168. if(symbol)
  169. {
  170. if(Source *source=symbol->source)
  171. {
  172. markCurPos();
  173. Source *old=cur();
  174. cur(source);
  175. if(InRange(symbol->token_index, source->tokens))
  176. {
  177. Token &token=*source->tokens[symbol->token_index];
  178. source->highlight(token.lineIndex(), old!=cur());
  179. source->sel=-1;
  180. source->cur.set(token.col, token.lineIndex());
  181. markCurPos();
  182. }
  183. }else
  184. if(symbol->type==Symbol::KEYWORD)
  185. {
  186. Str comments=symbol->comments();
  187. if( comments.is())Gui.msgBox(S+"Keyword \""+*symbol+"\"", comments);
  188. }
  189. }
  190. }
  191. /******************************************************************************/
  192. void CodeEditor::findAllReferences(C Str &text)
  193. {
  194. buildClear();
  195. FREPA(sources)if(Find::FilterScope(&sources[i], Find::ALL))
  196. {
  197. Source &source=sources[i];
  198. Bool found =false;
  199. FREPA(source.lines)
  200. {
  201. Line &line=source.lines[i];
  202. if(Contains(line, text, true, true))
  203. {
  204. if(!found){found=true; buildNew().set(S+"\""+source.loc.asText()+"\":", &source);}
  205. buildNew().set(S+" "+line, &line);
  206. }
  207. }
  208. }
  209. buildUpdate();
  210. }
  211. /******************************************************************************/
  212. void CodeEditor::findAllReferences(Symbol *symbol)
  213. {
  214. if(symbol)
  215. {
  216. Str symbol_name=symbol->shortName();
  217. buildClear();
  218. Line *last_line=null;
  219. FREPA(sources)if(Find::FilterScope(&sources[i], Find::ALL))
  220. {
  221. Source &source=sources[i];
  222. Bool found =false;
  223. FREPA(source.tokens)
  224. {
  225. Token &token=*source.tokens[i];
  226. if(token.line!=last_line && token==symbol_name)
  227. {
  228. source.parseFunc(token);
  229. if(Symbol *token_symbol=source.finalSymbol(i)) // always calculate because 'token.symbol' can be equal to FUNC_LIST or data type (not var)
  230. if(token_symbol->sameSymbol(*symbol)) // if the same symbol
  231. {
  232. if(!found){found=true; buildNew().set(S+"\""+source.loc.asText()+"\":", &source);}
  233. buildNew().set(S+" "+*token.line, token.line);
  234. last_line=token.line;
  235. }
  236. }
  237. }
  238. }
  239. buildUpdate();
  240. }
  241. }
  242. /******************************************************************************/
  243. void CodeEditor::findAllReferences(C UID &id)
  244. {
  245. // TODO: support this
  246. }
  247. /******************************************************************************/
  248. }}
  249. /******************************************************************************/