Git Product home page Git Product logo

akvelon / flutter-code-editor Goto Github PK

View Code? Open in Web Editor NEW
191.0 12.0 46.0 4.24 MB

Flutter Code Editor is a multi-platform code editor supporting syntax highlighting, code blocks folding, autocompletion, read-only code blocks, hiding specific code blocks, themes, and more.

Home Page: https://akvelon.com

License: Apache License 2.0

Kotlin 0.02% Shell 0.06% Ruby 0.21% Swift 0.06% Objective-C 0.01% Dart 97.28% HTML 0.23% CMake 1.36% C++ 0.67% C 0.11%
code-blocks code-editor code-editor-mobile code-editor-online flutter syntax-highlighting code-folding code-hiding theme

flutter-code-editor's Introduction

Flutter Code Editor

Pub Version CodeFactor codecov

Flutter Code Editor is a multi-platform code editor supporting:

  • Syntax highlighting for over 100 languages,
  • Code blocks folding,
  • Autocompletion,
  • Read-only code blocks,
  • Hiding specific code blocks,
  • Themes,
  • And many other features.

Basic example

Basic Usage

import 'package:flutter/material.dart';
import 'package:flutter_code_editor/flutter_code_editor.dart';
import 'package:flutter_highlight/themes/monokai-sublime.dart';
import 'package:highlight/languages/java.dart';

void main() {
  runApp(const CodeEditor());
}

final controller = CodeController(
  text: '...', // Initial code
  language: java,
);

class CodeEditor extends StatelessWidget {
  const CodeEditor();

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: CodeTheme(
          data: CodeThemeData(styles: monokaiSublimeTheme),
          child: SingleChildScrollView(
            child: CodeField(
              controller: controller,
            ),
          ),
        ),
      ),
    );
  }
}

See the full runnable example here.

Languages

Syntax Highlighting

Flutter Code Editor supports over a hundred languages, relying on the highlight package for parsing code.

To select a language, use a corresponding variable:

import 'package:highlight/languages/python.dart'; // Each language is defined in its file.

final controller = CodeController(
  text: '...', // Initial code
  language: python,
);

Language can be dynamically changed on a controller:

controller.setLanguage(go, DefaultLocalAnalyzer());

Code Blocks Folding

Flutter Code Editor can detect and fold code blocks. Code blocks folding is supported for the following languages:

  • Dart
  • Go
  • Java
  • Python
  • Scala

Foldable blocks example

Code blocks folding may support other languages in experimental mode.

Code Analysis

The editor supports pluggable analyzers to highlight errors and show error messages:

DartPadAnalyzer

We ship the following analyzers:

  • DefaultLocalAnalyzer highlights unmatched pair characters for supported languages. It works on the client locally, and is selected by default on CodeController if no other analyzer is specified.
  • DartPadAnalyzer for Dart language, calls upon the DartPad backend for analysis.

For other languages, you can write custom analyzers that access your backend. See the code for DartPadAnalyzer for the implementation example.

To set the analyzer, call any of the following:

codeController = CodeController(language: dart, analyzer: DartPadAnalyzer());
codeController.analyzer = DartPadAnalyzer();
codeController.setLanguage(dart, analyzer: DartPadAnalyzer());

Note: Code analysis is an experimental feature. We may introduce breaking changes to Analyzer subclasses without following the semver contract. If you only use the analyzers we ship, then this will not affect you.

Themes

Pre-defined Themes

Flutter Code Editor supports themes from the highlight package — see the full list of the pre-defined themes here.

Use CodeTheme widget to set the theme for underlying editors:

return MaterialApp(
  home: Scaffold(
    body: CodeTheme(
      data: CodeThemeData(styles: monokaiSublimeTheme), // <= Pre-defined in flutter_highlight.
      child: SingleChildScrollView(
        child: CodeField(
          controller: controller,
        ),
      ),
    ),
  ),
);

Custom Themes

To use a custom theme, create a map of styles under the pre-defined class names — see this example.

Hiding Line Numbers, Errors, and Folding Handles

A lot of styling can be tuned with a GutterStyle object passed to a CodeField widget. See this example that dynamically changes the properties listed here.

CodeField(
  gutterStyle: GutterStyle(
    showErrors: false,
    showFoldingHandles: false,
    showLineNumbers: false,
  ),
  // ...
),

If you want to hide the entire gutter, use GutterStyle.none constant instead:

CodeField(
  gutterStyle: GutterStyle.none,
  // ...
),

Accessing the Text

CodeController extends the Flutter's built-in TextEditingController and is immediately usable as one. However, code folding and other features have impact on built-in properties:

  • text returns and sets the visible text. If any code is folded, it will not be returned.
  • value returns and sets the TextEditingValue with the visible text and selection. If any code is folded, it will not be returned.
  • fullText returns and sets the entire text, including any folded blocks and hidden service comments (see below).

Named Sections

To manipulate parts of the source code, Flutter Code Editor supports named sections. They are defined in the code by adding tags that Flutter Code Editor recognizes.

To define a named section in your source code, add comments to tag the start and the end of the section:

  1. Add comment [START section_name] to tag the beginning of the section.
  2. Add comment [END section_name] to tag the end of the section.

Here is an example to define a named section section1:

final text = '''
class MyClass {
    public static void main(String[] args) {// [START section1]
        int num = 5;
        System.out.println("Factorial of " + num + " is " + factorial(5));
    }// [END section1]
}
''';

To process named sections in the Flutter Code Editor, pass the named section parser to the controller:

final controller = CodeController(
  text: text,
  language: java,
  namedSectionParser: const BracketsStartEndNamedSectionParser(), // NEW
);

The example above creates a section named section1. The built-in BracketsStartEndNamedSectionParser class is designed to parse sections from the code comments using the above syntax. It also hides any single-line comment that has a section tag with the above syntax, although such comments are still present in the editor's hidden state and will be revealed when copying the text.

To customize section parsing using any other syntax, subclass AbstractNamedSectionParser.

Read-Only Code Blocks

Flutter Code Editor allows you to define read-only code blocks. This may be useful for learning use cases when users are guided to modify certain code blocks while other code is meant to be protected from changes.

To make a named section read-only, pass a set of named sections to the controller.readOnlySectionNames:

controller.readOnlySectionNames = {'section1'};

This locks the given sections from modifications in the Flutter Code Editor. Any non-existent section names in this set are ignored. To make the code editable again, pass an updated set to controller.readOnlySectionNames.

When using this feature, text and value properties cannot be used to change the text programmatically because they have the same effect as the user input. This means that locking affects them as well.

To change a partially locked controller, set the fullText property.

Readonly blocks example

Advanced Code Blocks Folding

Folding the First Comment/License

Many code snippets contain a license as their first comment, which can distract readers. To fold the first comment, use:

controller.foldCommentAtLineZero();

This method has no effect if there is no comment starting at the first line.

Folding Imports

In many languages, the editor recognizes sequential import lines and an optional package line as one foldable block. To fold such blocks:

controller.foldImports();

Named Sections

The editor supports folding all blocks except for specific named sections. This helps the user focus on those sections while all source code is still there and can be expanded and copied by the user.

To fold all blocks except those overlapping with the given named sections:

controller.foldOutsideSections(['section1']);

Folding Specific Blocks

To fold and unfold blocks at a given line number:

controller.foldAt(1);
controller.unfoldAt(1);

If there is no block at a given line, this has no effect.

Note: For the controller, line numbers start at 0 although the widget displays them starting at 1.

Accessing Folded Blocks

To get the currently folded blocks, read controller.code.foldedBlocks.

Hiding Text

The editor allows you to completely hide all code except for a specific named section. This is useful to achieve even more focus than with folding.

To hide all the code except the given named section:

controller.visibleSectionNames = {'section1'};

visibleSectionNames

When hiding text, the full text is still preserved and available via fullText property in the Flutter Code Editor.

Hiding text preserves line numbering, which is not possible by just showing a cropped snippet. Preserving hidden text is also useful if you later need to send the full code for further processing but still want to hide non-informative parts.

Hiding text also makes the entire editor read-only to prevent users from modifying the code, adding imports, etc. which may conflict with the hidden parts.

Only one visible section at a time is currently supported. The behavior of passing more than one section is undefined.

Autocompletion

The editor suggests words as they are typed. Suggested words are:

  • All keywords of the current language.
  • All words already in the text.
  • Words set with controller.autocompleter.setCustomWords(['word1', 'word2'])

All those words are merged into an unstructured dictionary. The editor does not perform any syntax analysis, so it cannot tell if a given class really has the method the user is typing. This feature is meant to simplify typing, but should not be relied on when exploring classes and methods.

Suggestions example

To disable autocompletion:

controller.popupController.enabled = false;

Shortcuts

  • Indent (Tab)
  • Outdent (Shift-Tab)

indent outdent example

  • Comment out (Control-/)
  • Uncomment (Control-/)

comment out uncomment example

Migration Guides

Contact Us

Contribution Guide

To get involved with Flutter Code Editor, submit your contribution as a PR, contact us with a feature request or question, or report an issue.

flutter-code-editor's People

Contributors

akosolapov avatar alexeyinkin avatar arinfaraj avatar ilya-kozyrev avatar ivebracke avatar malarg avatar mrshakirov avatar nausharipov avatar prateekmedia avatar yescorp avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

flutter-code-editor's Issues

Fix highlight package

Java highlighting breaks if # is present anywhere but string literals and comments:

public class MyClass {
}
#

Java highlighting beaks if a multiline string literal is present anywhere with single or double quotes:

public class MyClass {
  private string = """
multiline
""";
}

Python highlighting breaks if a block opening line is not terminated with ::

def fn()

Scala highlighting breaks if a multiline string literal is present anywhere:

val str4 = """
multiline
""";

Comply with the original license

This editor was forked from https://github.com/BertrandBev/code_field
which uses MIT License. It means we must do one of the following:

  • Mention the original author. Learn if MIT allows re-licensing to Apache license we currently use.
  • Mention the original author. Re-license our fork to MIT license.
  • Ask the original author to re-license the code under Apache license or public domain license.

Test read-only feature by simulating keyboard events

Navigation, Delete and Backspace are currently simulated with WidgetTester.sendKeyEvent. This triggers Flutter's Shortcuts mechanism. However, typing text cannot be simulated like this, and we merely set CodeController.value to the new value.

This is insufficient because it leaves key handlers untested while the read-only feature may evolve to use them and to block input there.

True end-of-line comment parsing

In #22, lines like var a = "//readonly "; were allowed to be falsely parsed as comments to make such strings read-only.
Need to implement the parser to only flag real end-of-line comments.

Corner cases:

  • Single line string literals with " //readonly ".
  • Multi-line string literals in """multi-line string""".
  • int /* // */ readonly ;.

Append if you spot more false positives.

Ctrl + Z combination changes the code in editor but not the value of the Catalog field

Precondition:
"Sample A" - current example.
"Sample B" - an example we will be switching to.
User is on the main page. Example "Sample A" is opened in editor.

Steps to reproduce:

  1. Type anything in editor.
  2. Click on the dropdown with examples.
  3. Pick any other example.
  4. The example in the editor switched to the selected one (Sample B is our current example now).
  5. Press Ctrl + Z in the editor

Expected Result:
Nothing happens. (According to the prod page)
Acutal Result:
Previous example "Sample A" appears, but selected value in the Catalog dropdown field stays the same.

Line numbering gaps for hidden text

Currently hidden text ranges are only created inside a line, so we never needed to break line numbering.
In future, we will have hidden ranges that span multiple lines, so we need gaps.

Also line numbering has not been refactored after forking, so there must be something to get in order.

Named sections parsing

In code, there may be many names sections designated like this:

editable
[START section_name]
readonly
readonly
[END section_name]
editable

They will be used for read-only functionality, for initially collapsing blocks, and for hidden sections.
We need to parse them into Code object to get started on those features.

Hide service comments

Service comments like //readonly and //[START section1] should be hidden in the editor.

Read-only by named sections

In #22, we added read-only blocks by new line blocks. Now we need to allow read-only blocks by named sections like:

editable
[START section_name]
readonly
readonly
[END section_name]
editable

This should work if the given section_name is passed as a read-only section. Multiple such section names are allowed to be read-only.

Add CodeField.lineNumbers from BertrandBev

This feature was added to the original editor since forking. Need to add it to the fork. We do not use it but, but it will be easier to merge future useful features if we keep the diff low.

Read-only by end-of-line comments

Support read-only parts of code, designated by end-of-line comments.
If the comment contains lowercase readonly, this line is read-only.

At this point, do not parse strings like var a = "//readonly", this is allowed to be false-positive read-only.

Hidden comments generate foldable blocks

Dmitry Repin
[5:08 PM]

(https://akvelon.slack.com/archives/D041YQ1E1B4/p1662988084068089)
FoldableBlock(startLine: 0, endLine: 6, type: FoldableBlockType.braces)
FoldableBlock(startLine: 1, endLine: 2, type: FoldableBlockType.braces)
FoldableBlock(startLine: 2, endLine: 3, type: FoldableBlockType.singleLineComment)
FoldableBlock(startLine: 4, endLine: 5, type: FoldableBlockType.braces)
###
class MyClass {
  void readOnlyMethod() {// [START section1]
  }// [END section1]
  // [START section2]
  void method() {
  }// [END section2]
}

Reusing a RegExp causes a JavaScript error

Steps to reproduce:

  1. Start the example app.
  2. Click to the bottom empty line.
  3. Press Enter.
  4. Click to readOnlyMethod method name.
  5. Press Enter.

Expected: Nothing happens.
Acutal: Cursor is moved to the bottom, an empty line is added there.

Reproducible in:

  • Web, Flutter 3.3, with the message in the console (see below).
  • Web, Flutter 3.0, no messages in console.

Not reproducible in Linux Desktop.

vokoscreen-2022-09-07_16-21-41.mp4

Found in commit: 72caacd 72caacd2975e80e0c3e3f477b6d82c7b0ef271ce

Error in the IDE debug output
======== Exception caught by services library ======================================================
The following JSNoSuchMethodError was thrown during method call TextInputClient.updateEditingState:
TypeError: Cannot read properties of null (reading 'Symbol(dartx.length)')

When the exception was thrown, this was the stack: 
dart:sdk_internal 29437:17                                                      regExpCaptureCount
dart:sdk_internal 18584:70                                                      split]
packages/flutter_code_editor/src/autocomplete/autocompleter.dart.lib.js 138:32  [_updateText]
packages/flutter_code_editor/src/autocomplete/autocompleter.dart.lib.js 123:24  setText
packages/flutter_code_editor/src/code_field/code_controller.dart.lib.js 464:28  set value
packages/flutter/src/widgets/title.dart.lib.js 41746:36                         set [_value]
packages/flutter/src/widgets/title.dart.lib.js 42015:24                         [_formatAndSetValue]
packages/flutter/src/widgets/title.dart.lib.js 41557:35                         updateEditingValue
packages/flutter/src/services/text_editing_delta.dart.lib.js 3243:66            _handleTextInputInvocation
dart:sdk_internal 40595:34                                                      runBody
dart:sdk_internal 40626:7                                                       _async
packages/flutter/src/services/text_editing_delta.dart.lib.js 3167:20            [_handleTextInputInvocation]
packages/flutter/src/services/text_editing_delta.dart.lib.js 3154:56            _loudlyHandleTextInputInvocation
dart:sdk_internal 40595:34                                                      runBody
dart:sdk_internal 40626:7                                                       _async
packages/flutter/src/services/text_editing_delta.dart.lib.js 3152:20            [_loudlyHandleTextInputInvocation]
packages/flutter/src/services/text_editing_delta.dart.lib.js 4436:57            _handleAsMethodCall
dart:sdk_internal 40595:34                                                      runBody
dart:sdk_internal 40626:7                                                       _async
packages/flutter/src/services/text_editing_delta.dart.lib.js 4433:20            [_handleAsMethodCall]
packages/flutter/src/services/text_editing_delta.dart.lib.js 4430:126           <fn>
packages/flutter/src/services/text_editing_delta.dart.lib.js 9104:31            <fn>
dart:sdk_internal 40595:34                                                      runBody
dart:sdk_internal 40626:7                                                       _async
packages/flutter/src/services/text_editing_delta.dart.lib.js 9101:82            <fn>
dart:sdk_internal 196990:7                                                      invoke2
dart:sdk_internal 133154:15                                                     invoke
dart:sdk_internal 133225:54                                                     push
dart:sdk_internal 133316:19                                                     push
dart:sdk_internal 172366:27                                                     invokeOnPlatformMessage
dart:sdk_internal 187512:49                                                     updateEditingState
dart:sdk_internal 187594:26                                                     <fn>
dart:sdk_internal 179063:38                                                     handleChange
dart:sdk_internal 5438:16                                                       _checkAndCall
dart:sdk_internal 5443:17                                                       dcall
dart:sdk_internal 62137:21                                                      ret
call: MethodCall(TextInputClient.updateEditingState, [1, {text: class MyClass {
  void readOnlyMethod() {
  }
  
  void method() {
  }
}

, selectionBase: 74, selectionExtent: 74, composingBase: null, composingExtent: null}])
====================================================================================================

No errors in browser console.

autocompleter.dart, Failing _updateText
  void _updateText(AutoComplete ac, String text) {
    ac.clearEntries();
    ac.enterList(
      text
          .split(RegExps.wordSplit)
          .where((t) => t.isNotEmpty)
          .toList(growable: false),
    );
  }
autocompleter.dart, Working _updateText
  void _updateText(AutoComplete ac, String text) {
    ac.clearEntries();
    ac.enterList(
      text
          .split(RegExp(RegExps.wordSplit.pattern))
          .where((t) => t.isNotEmpty)
          .toList(growable: false),
    );
  }
flutter doctor -v
[✓] Flutter (Channel stable, 3.3.0, on Ubuntu 20.04.4 LTS 5.14.0-1051-oem, locale en_US.UTF-8)
    • Flutter version 3.3.0 on channel stable at /home/alexey/snap/flutter/common/flutter
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision ffccd96b62 (9 days ago), 2022-08-29 17:28:57 -0700
    • Engine revision 5e9e0e0aa8
    • Dart version 2.18.0
    • DevTools version 2.15.0

[!] Android toolchain - develop for Android devices (Android SDK version 33.0.0)
    • Android SDK at /home/alexey/Android/Sdk
    ✗ cmdline-tools component is missing
      Run `path/to/sdkmanager --install "cmdline-tools;latest"`
      See https://developer.android.com/studio/command-line for more details.
    ✗ Android license status unknown.
      Run `flutter doctor --android-licenses` to accept the SDK licenses.
      See https://flutter.dev/docs/get-started/install/linux#android-setup for more details.

[✓] Chrome - develop for the web
    • Chrome at google-chrome

[✓] Linux toolchain - develop for Linux desktop
    • clang version 6.0.0-1ubuntu2 (tags/RELEASE_600/final)
    • cmake version 3.10.2
    • ninja version 1.8.2
    • pkg-config version 0.29.1

[✓] Android Studio (version 2021.2)
    • Android Studio at /home/alexey/bin/android-studio
    • Flutter plugin version 68.1.2
    • Dart plugin version 212.5744
    • Java version OpenJDK Runtime Environment (build 11.0.12+0-b1504.28-7817840)

[✓] VS Code (version 1.70.2)
    • VS Code at /usr/share/code
    • Flutter extension can be installed from:
      🔨 https://marketplace.visualstudio.com/items?itemName=Dart-Code.flutter

[✓] Connected device (2 available)
    • Linux (desktop) • linux  • linux-x64      • Ubuntu 20.04.4 LTS 5.14.0-1051-oem
    • Chrome (web)    • chrome • web-javascript • Google Chrome 104.0.5112.101

[✓] HTTP Host Availability
    • All required HTTP hosts are available

! Doctor found issues in 1 category.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.