1 module dlangide.tools.d.deditorTool;
2 
3 import dlangide.tools.editorTool;
4 import dlangide.tools.d.dcdinterface;
5 import dlangide.ui.dsourceedit;
6 import dlangui.widgets.editors;
7 import dlangide.ui.frame;
8 import std.stdio;
9 import std.string;
10 import std.utf;
11 import dlangui.core.logger;
12 
13 import std.conv;
14 
15 // TODO: async operation in background thread
16 // TODO: effective caretPositionToByteOffset/byteOffsetToCaret impl
17 
18 class DEditorTool : EditorTool 
19 {
20 
21 
22 	this(IDEFrame frame) {
23 		_dcd = new DCDInterface(DCD_SERVER_PORT_FOR_DLANGIDE);
24 		super(frame);
25 	}
26 
27 	override bool goToDefinition(DSourceEdit editor, TextPosition caretPosition) {
28         string[] importPaths = editor.importPaths();
29         string content = toUTF8(editor.text);
30 		auto byteOffset = caretPositionToByteOffset(content, caretPosition);
31 		ResultSet output = _dcd.goToDefinition(importPaths, editor.filename, content, byteOffset);
32 
33 
34 		switch(output.result) {
35 			//TODO: Show dialog
36 			case DCDResult.FAIL:
37 			case DCDResult.DCD_NOT_RUNNING:
38 			case DCDResult.NO_RESULT:
39                 editor.setFocus();
40 				return false;
41 			case DCDResult.SUCCESS:
42 				auto target = to!int(output.output[1]);
43 				if(output.output[0].indexOf("stdin".dup) != -1) {
44 					Log.d("Declaration is in current file. Jumping to it.");
45 					auto destPos = byteOffsetToCaret(content, target);
46 					editor.setCaretPos(destPos.line,destPos.pos);
47                     editor.setFocus();
48 				}
49 				else {
50 					//Must open file first to get the content for finding the correct caret position.
51     				_frame.openSourceFile(to!string(output.output[0]));
52                     string txt;
53                     txt = toUTF8(_frame.currentEditor.text);
54 					auto destPos = byteOffsetToCaret(txt, target);
55 					_frame.currentEditor.setCaretPos(destPos.line,destPos.pos);
56                     _frame.currentEditor.setFocus();
57         		}
58         		return true;
59         	default:
60         		return false;
61 		}
62     }
63 
64     override dstring[] getCompletions(DSourceEdit editor, TextPosition caretPosition) {
65         string[] importPaths = editor.importPaths();
66 
67         string content = toUTF8(editor.text);
68 		auto byteOffset = caretPositionToByteOffset(content, caretPosition);
69 		ResultSet output = _dcd.getCompletions(importPaths, editor.filename, content, byteOffset);
70 		switch(output.result) {
71 			//TODO: Show dialog
72 			case DCDResult.FAIL:
73 			case DCDResult.DCD_NOT_RUNNING:
74 			case DCDResult.NO_RESULT:
75 			case DCDResult.SUCCESS:
76         	default:
77         		return output.output;
78 		}
79     }
80 
81 private:
82 	DCDInterface _dcd;
83 
84 	int caretPositionToByteOffset(string content, TextPosition caretPosition) {
85 		auto line = 0;
86 		auto pos = 0;
87 		auto bytes = 0;
88 		foreach(c; content) {
89 			bytes++;
90 			if(c == '\n') {
91 				line++;
92 			}
93 			if(line == caretPosition.line) {
94 				if(pos == caretPosition.pos)
95 					break;
96 				pos++;
97 			}
98 		}
99 		return bytes;
100 	}
101 
102 	TextPosition byteOffsetToCaret(string content, int byteOffset) {
103 		int bytes = 0;
104 		int line = 0;
105 		int pos = 0;
106 		TextPosition textPos;
107 		foreach(c; content) {
108 			if(bytes == byteOffset) {
109 	            //We all good.
110 	            textPos.line = line;
111 	            textPos.pos = pos;
112 	            return textPos;
113         	}
114         	bytes++;
115         	if(c == '\n')
116 	        {
117 	        	line++;
118 	        	pos = 0;
119 	        }
120 	        else {
121         		pos++;
122         	}
123     	}
124     	return textPos;
125 	}
126 }