@tduncan / Cortana / commits / 51b319c

fix #10 : add support for reasoning tokens and fallback to plain text for unsupported syntax highlighting languages

fix #10 : add support for reasoning tokens and fallback to plain text for unsupported syntax highlighting languages

abdulmominsakib committed May 23, 2026 at 20:36 UTC 51b319c281db4f0f4c081b6dd3502f0a4bf053b7
3 files changed +58 -30
lib/core/providers/highlighter_provider.dart
+3 -3
@@ -1,7 +1,7 @@
1 import 'package:flutter_riverpod/flutter_riverpod.dart';
2 import 'package:syntax_highlight/syntax_highlight.dart';
3
4 -const _languages = [
4 +const supportedHighlighterLanguages = {
5 'css',
6 'dart',
7 'go',
@@ -16,7 +16,7 @@ const _languages = [
16 'swift',
17 'typescript',
18 'yaml',
19 -];
19 +};
20
21 final highlighterThemesProvider = FutureProvider<HighlighterThemes>((ref) {
22 return HighlighterThemes.load();
@@ -36,5 +36,5 @@ class HighlighterThemes {
36 }
37
38 Future<void> initializeHighlighter() async {
39 - await Highlighter.initialize(_languages);
39 + await Highlighter.initialize(supportedHighlighterLanguages.toList());
40 }
lib/features/chat/data/chat_service.dart
+17 -6
@@ -678,12 +678,23 @@ class OllamaChatService implements ChatService {
678 if (line.isNotEmpty) {
679 try {
680 final json = jsonDecode(line) as Map<String, dynamic>;
681 - final content = json['message']?['content'];
682 - if (content != null && content is String) {
683 - yield ChatResponse(
684 - type: ChatResponseType.message,
685 - content: content,
686 - );
681 + final message = json['message'];
682 + if (message != null && message is Map<String, dynamic>) {
683 + final content = message['content'] as String?;
684 + final thinking = message['thinking'] as String?;
685 +
686 + if (thinking != null && thinking.isNotEmpty) {
687 + yield ChatResponse(
688 + type: ChatResponseType.reasoning,
689 + reasoningContent: thinking,
690 + );
691 + }
692 + if (content != null && content.isNotEmpty) {
693 + yield ChatResponse(
694 + type: ChatResponseType.message,
695 + content: content,
696 + );
697 + }
698 }
699 if (json['done'] == true) {
700 yield const ChatResponse(type: ChatResponseType.done);
lib/features/chat/views/components/code_block.dart
+38 -21
@@ -131,27 +131,44 @@ class CodeBlock extends ConsumerWidget {
131 ),
132 themes.when(
133 data: (themesData) {
134 - final loadedTheme = isDark ? themesData.dark : themesData.light;
135 - final highlighter = Highlighter(
136 - language: languageName.isNotEmpty ? languageName : 'dart',
137 - theme: loadedTheme,
138 - );
139 - return SingleChildScrollView(
140 - scrollDirection: Axis.horizontal,
141 - padding: const EdgeInsets.all(12),
142 - child: SelectableText.rich(
143 - TextSpan(
144 - style: const TextStyle(
145 - fontFamily: 'monospace',
146 - fontSize: 13,
147 - height: 1.5,
148 - ),
149 - children: <TextSpan>[
150 - highlighter.highlight(code),
151 - ],
152 - ),
153 - ),
154 - );
134 + final loadedTheme = isDark ? themesData.dark : themesData.light;
135 + final effectiveLanguage = languageName.isNotEmpty ? languageName : 'dart';
136 +
137 + if (supportedHighlighterLanguages.contains(effectiveLanguage)) {
138 + final highlighter = Highlighter(
139 + language: effectiveLanguage,
140 + theme: loadedTheme,
141 + );
142 + return SingleChildScrollView(
143 + scrollDirection: Axis.horizontal,
144 + padding: const EdgeInsets.all(12),
145 + child: SelectableText.rich(
146 + TextSpan(
147 + style: const TextStyle(
148 + fontFamily: 'monospace',
149 + fontSize: 13,
150 + height: 1.5,
151 + ),
152 + children: <TextSpan>[
153 + highlighter.highlight(code),
154 + ],
155 + ),
156 + ),
157 + );
158 + } else {
159 + return SingleChildScrollView(
160 + scrollDirection: Axis.horizontal,
161 + padding: const EdgeInsets.all(12),
162 + child: SelectableText(
163 + code,
164 + style: const TextStyle(
165 + fontFamily: 'monospace',
166 + fontSize: 13,
167 + height: 1.5,
168 + ),
169 + ),
170 + );
171 + }
172 },
173 loading: () => SingleChildScrollView(
174 scrollDirection: Axis.horizontal,