CodeForgeController constructor
CodeForgeController({
- LspConfig? lspConfig,
Implementation
CodeForgeController({this.lspConfig}) {
_listeners.add(() {
if (isBufferActive) {
final col = bufferCursorColumn;
final lineText = bufferLineText ?? '';
if (col > 0 && col <= lineText.length) {
_insertedChar = lineText.substring(col - 1, col);
}
} else {
final base = _prevSelection.baseOffset.clamp(0, text.length);
final extent = selection.baseOffset.clamp(0, text.length);
if (extent - base == 1) {
_insertedChar = text.substring(base, extent);
} else if (extent > 0) {
final cursor = selection.baseOffset.clamp(0, text.length);
if (cursor > 0) {
_insertedChar = text.substring(cursor - 1, cursor);
}
}
}
_isTyping = _insertedChar.isNotEmpty && _isAlpha(_insertedChar);
});
if (lspConfig != null) {
(() async {
try {
if (lspConfig is LspSocketConfig) {
await (lspConfig! as LspSocketConfig).connect();
}
if (!lspConfig!.isIntialized) {
await lspConfig!.initialize();
}
await Future.delayed(const Duration(milliseconds: 300));
await lspConfig!.openDocument(openedFile!);
_lspReady = true;
await _fetchSemanticTokensFull();
} catch (e) {
debugPrint('Error initializing LSP: $e');
} finally {
_listeners.add(_highlightListener);
}
})();
_lspResponsesSubscription = lspConfig!.responses.listen((data) async {
try {
if (data['method'] == 'workspace/applyEdit') {
final Map<String, dynamic>? params = data['params'];
if (params != null && params.isNotEmpty) {
if (params.containsKey('edit')) {
await applyWorkspaceEdit(params);
}
}
}
if (data['method'] == 'textDocument/publishDiagnostics') {
final List<dynamic> rawDiagnostics =
data['params']?['diagnostics'] ?? [];
if (rawDiagnostics.isNotEmpty) {
final List<LspErrors> errors = [];
for (final item in rawDiagnostics) {
if (item is! Map<String, dynamic>) continue;
int severity = item['severity'] ?? 0;
if (severity == 1 && lspConfig!.disableError) {
severity = 0;
}
if (severity == 2 && lspConfig!.disableWarning) {
severity = 0;
}
if (severity > 0) {
errors.add(
LspErrors(
severity: severity,
range: item['range'],
message: item['message'] ?? '',
),
);
}
}
if (!_isDisposed) diagnostics.value = errors;
_codeActionTimer?.cancel();
_codeActionTimer = Timer(
const Duration(milliseconds: 250),
() async {
if (errors.isEmpty) {
if (!_isDisposed) codeActions.value = null;
return;
}
int minStartLine = errors
.map((d) => d.range['start']?['line'] as int? ?? 0)
.reduce((a, b) => a < b ? a : b);
int minStartChar = errors
.map((d) => d.range['start']?['character'] as int? ?? 0)
.reduce((a, b) => a < b ? a : b);
int maxEndLine = errors
.map((d) => d.range['end']?['line'] as int? ?? 0)
.reduce((a, b) => a > b ? a : b);
int maxEndChar = errors
.map((d) => d.range['end']?['character'] as int? ?? 0)
.reduce((a, b) => a > b ? a : b);
try {
final actions = await lspConfig!.getCodeActions(
filePath: openedFile!,
startLine: minStartLine,
startCharacter: minStartChar,
endLine: maxEndLine,
endCharacter: maxEndChar,
diagnostics: rawDiagnostics.cast<Map<String, dynamic>>(),
);
if (!_isDisposed) codeActions.value = actions;
} catch (e) {
debugPrint('Error fetching code actions: $e');
}
},
);
} else {
if (!_isDisposed) diagnostics.value = [];
}
}
} catch (e, st) {
debugPrint('Error handling LSP response: $e\n$st');
}
});
} else {
_listeners.add(() {
final cursorPosition = selection.extentOffset;
final prefix = getCurrentWordPrefix(text, cursorPosition);
if (_isTyping && selection.extentOffset > 0) {
final regExp = RegExp(r'\b\w+\b');
final List<String> words = regExp
.allMatches(text)
.map((m) => m.group(0)!)
.toList();
String currentWord = '';
if (text.isNotEmpty) {
final match = RegExp(r'\w+$').firstMatch(text);
if (match != null) {
currentWord = match.group(0)!;
}
}
_suggestions.clear();
for (final i in words) {
if (!_suggestions.contains(i) && i != currentWord) {
_suggestions.add(i);
}
}
if (prefix.isNotEmpty) {
_suggestions = _suggestions
.where((s) => s.startsWith(prefix))
.toList();
}
_sortSuggestions(prefix);
final triggerChar = text[cursorPosition - 1];
if (!_isAlpha(triggerChar)) {
if (!_isDisposed) suggestions.value = null;
return;
}
if (!_isDisposed) suggestions.value = _suggestions;
} else {
if (!_isDisposed) suggestions.value = null;
}
});
}
}