Code Monkey home page Code Monkey logo

code_field's Introduction

CodeField

A customizable code text field supporting syntax highlighting

Pub Website shields.io GitHub license Awesome Flutter

Live demo

A live demo showcasing a few language / theme combinations

Showcase

The experimental VM dlox uses CodeField in its online editor

Features

  • Code highlight for 189 built-in languages with 90 themes thanks to flutter_highlight
  • Easy language highlight customization through the use of theme maps
  • Fully customizable code field style through a TextField like API
  • Handles horizontal/vertical scrolling and vertical expansion
  • Supports code modifiers
  • Works on Android, iOS, Web, MacOS, Windows, and Linux

Code modifiers help manage indents automatically

The editor is wrapped in a horizontal scrollable container to handle long lines

Installing

In the pubspec.yaml of your flutter project, add the following dependency:

dependencies:
  ...
  code_text_field: <latest_version>

latest version

In your library add the following import:

import 'package:code_text_field/code_text_field.dart';

Simple example

A CodeField widget works with a CodeController which dynamically parses the text input according to a language and renders it with a theme map

import 'package:flutter/material.dart';
import 'package:code_text_field/code_text_field.dart';
// Import the language & theme
import 'package:highlight/languages/dart.dart';
import 'package:flutter_highlight/themes/monokai-sublime.dart';

class CodeEditor extends StatefulWidget {
  @override
  _CodeEditorState createState() => _CodeEditorState();
}

class _CodeEditorState extends State<CodeEditor> {
  CodeController? _codeController;

  @override
  void initState() {
    super.initState();
    final source = "void main() {\n    print(\"Hello, world!\");\n}";
    // Instantiate the CodeController
    _codeController = CodeController(
      text: source,
      language: dart,
    );
  }

  @override
  void dispose() {
    _codeController?.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return CodeTheme(
      data: const CodeThemeData(styles: monokaiSublimeTheme),
      child: CodeField(
        controller: _codeController!,
        textStyle: const TextStyle(fontFamily: 'SourceCode'),
      ),
    );
  }
}

Here, the monospace font Source Code Pro has been added to the assets folder and to the pubspec.yaml file.

Parser options

On top of a language definition, word-wise styling can be specified in the stringMap field

_codeController = CodeController(
  //...
  stringMap: {
    "Hello": TextStyle(fontWeight: FontWeight.bold, color: Colors.red),
    "world": TextStyle(fontStyle: FontStyle.italic, color: Colors.green),
  },
);

More complex regexes may also be used with the patternMap. When a language is used though, its regexes patterns take precedence over patternMap and stringMap.

_codeController = CodeController(
  //...
  patternMap: {
    r"\B#[a-zA-Z0-9]+\b":
        TextStyle(fontWeight: FontWeight.bold, color: Colors.purpleAccent),
  },
);

Both patternMap and stringMap can be used without specifying a language.

_codeController = CodeController(
  text: source,
  patternMap: {
    r'".*"': TextStyle(color: Colors.yellow),
    r'[a-zA-Z0-9]+\(.*\)': TextStyle(color: Colors.green),
  },
  stringMap: {
    "void": TextStyle(fontWeight: FontWeight.bold, color: Colors.red),
    "print": TextStyle(fontWeight: FontWeight.bold, color: Colors.blue),
  },
);

Code Modifiers

Code modifiers can be created to react to special keystrokes. The default modifiers handle tab to space & automatic indentation. Here's the implementation of the default TabModifier

class TabModifier extends CodeModifier {
  const TabModifier() : super('\t');

  @override
  TextEditingValue? updateString(
      String text, TextSelection sel, EditorParams params) {
    final tmp = replace(text, sel.start, sel.end, " " * params.tabSpaces);
    return tmp;
  }
}

API

CodeField

const CodeField({
    Key? key,
    required this.controller,
    this.minLines,
    this.maxLines,
    this.expands = false,
    this.wrap = false,
    this.background,
    this.decoration,
    this.textStyle,
    this.padding = EdgeInsets.zero,
    this.lineNumberStyle = const LineNumberStyle(),
    this.enabled,
    this.onTap,
    this.readOnly = false,
    this.cursorColor,
    this.textSelectionTheme,
    this.lineNumberBuilder,
    this.focusNode,
    this.onChanged,
    this.isDense = false,
    this.smartQuotesType,
    this.keyboardType,
    this.lineNumbers = true,
    this.horizontalScroll = true,
    this.selectionControls,
    this.hintText,
    this.hintStyle,
  })

LineNumberStyle

  const LineNumberStyle({
    this.width = 42.0,
    this.textAlign = TextAlign.right,
    this.margin = 10.0,
    this.textStyle,
    this.background,
  });

CodeController

CodeController({
    String? text,
    Mode? language,
    this.patternMap,
    this.stringMap,
    this.params = const EditorParams(),
    this.modifiers = const [
      IndentModifier(),
      CloseBlockModifier(),
      TabModifier(),
    ],
  }) 

Limitations

Notes

A breaking change to the TextEditingController was introduced in flutter beta, dev & master channels. The branch beta should comply with those changes.

code_field's People

Contributors

ahmet-ozberk avatar alexeyinkin avatar bertrandbev avatar corvusye avatar eseidel avatar gumbarros avatar ihorkozar avatar jarrodcolburn avatar jason810496 avatar kubastick avatar leoshusar avatar mack-at-pieces avatar quangson91 avatar shilangyu 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

code_field's Issues

CodeField read only

Very nice editor!
Would be nice to have a readOnly option in the CodeField and a onTextChanged callback.

Bug: colors changed in web when cursor is set

There is some bug in the live demo: i can scroll down and see the correctly highlighted area:
Снимок экрана 2021-07-23 в 17 59 21

However if i set the cursor the colors are changed:
Снимок экрана 2021-07-23 в 17 59 28

See "moveTo" color is changed.

It happens not in all the themes.
Let me know if you can reproduce it or i will provide more details on this.

README Update for theme and CodeTheme

Thanks for your open source contributions!

The README still shows usage of the once-deprecated and now-deleted theme argument for CodeController, where now a wrapping CodeTheme with CodeThemeData are needed.

Thanks for updating the executable examples, that made it straightforward to find a working usage.

Shifting scroll highlight when scrolling beyond bounds of code editor

I'm currently using the CodeEditor for MacOS and experiencing an issue where the scroll highlight shakes and shifts when dragging past the bounds of the CodeEditor.

I'm unsure where this issue lies, whether it be something wrong with my code or the editor itself, but perhaps @BertrandBev or @alexeyinkin you may be able to shed some light here.

@alexeyinkin I noticed you do not experience this problem in your project here (https://play.beam.apache.org/), so perhaps there's something I can do to also resolve this.

Video attached.

Pieces.Text.Highlight.Drag.Shift.mov

Move theme from CodeController to the widget tree

Theme feels alien in CodeController because the controller has to do with data manipulation, and the presentation should be handled by the widget tree.

For example, I make an editor with light and dark themes, and I need to switch them. Currently, I need to re-create the controller for this. Recently, I proposed to make CodeController.theme mutable so simplify this in #41. Now I think this is not enough as this is an imperative solution while we can go declarative for this.

I suggest to:

  1. Add CodeTheme inherited widget that should stick theme data in the widget tree.
  2. Look for this widget up the tree In CodeController.buildTextSpan. Grab its theme if found. Use the controller's theme if not.
  3. Drop the requirement for both language and theme to be present.
  4. Deprecate CodeController.theme for removal in one of the next breaking releases.

Make CodeController.theme mutable

Can we make theme mutable after the controller is created? I am working on an editor with light/dark modes, and I need to switch them. It currently requires re-creating the controller which comes with a burden to dispose the old one etc.

How do I use CodeModifiers ?

Hi, thanks for a great flutter package.

I need custom formatting and indentation for my flutter project. How can I use code modifiers? I am unable to use CodeModifier as it is not exposed in the package.

Make webSpaceFix default to false

When webSpaceFix is omitted (defaults to true), CodeController.text returns text with dots. For it to return the intact text, webSpaceFix should be passed as false. But when the bug that called for this hack is fixed, we want text property to return intact text without webSpaceFix.

This will mean a breaking change when the bug is fixed, and this change will not be noticed. But we rather want it to happen now to have less problems in the future.

Another option is to make it required to force users to set it. When the bug is fixed, we will remove this property forcing users to pay attention again.

But I think it is OK to just change the default value in the next breaking release and to mention it in migration doc -- because the impact of this bug is mild.

Question autocomplete

hi, any tips how to implement autocomplete and snippets for desktop? thanks. I wonder if this is even possible.

Enable Selection for disabled Textfield

Hi,

I am using the CodeField mainly for displaying code, rather then writing it. So mainly I have it "enabled = false". Nonetheless I'd like to select some code snippets here and there, but as I see, the selection is only possible on enabled/writeable Textfields.

Is this possible?

Thanks in advance,
Mark

[Enhancement] Improve performance, when huge block of code is edited

When I am editing a huge block of code, the editor feels a bit sluggish.
This is probably happening because on each change, the whole block of code is being parsed for highlighting.
Is there any way that can improve the performance? I was thinking, if the parsing can be debounced somehow, that might improve the performance.

Desktop build

I could build the example for Linux target by removing the dependency to keyboard_visibility.
It involved to remove the package dependency in pubspec.yaml, and to comment / remove lines 7, 115-116, 129-130 in code_field.dart.

I don't know how much the keyboard_visibility is necessary on mobile platforms, but it would be great to find a way to have a fully cross platform package for this project.

If this dependency is necessary, maybe we could find another way to achieve it without dependency, just by handwritten code (I think I already made something like that in an app).

What do you think about that ?

Dotted spaces on macos

Using:

code_text_field: ^1.0.1-2

Having the following source code:

return new CodeField(
      controller: this._controller,
      textStyle: TextStyle(fontFamily: 'SourceCode'),
      lineNumberStyle: LineNumberStyle(),
      expands: true,
    );

It looks good in browser:
Снимок экрана 2021-08-25 в 18 32 15

but on macos the spaces are dotted:
Снимок экрана 2021-08-25 в 18 33 36

Is it code_field issue? Any workaround?
I'm happy to assist if necessary.

[code_text_field] How can I get changing value of code?

Hello,
I want to get changing value of code snippet.
Is there any way to get it?
For example, the initial code snippet is 'print("hello python")', and I add 'print("HWY")'.
Then, How can I get the value of 'print("hello python") print("HWY")'?

Screen Shot 2022-06-09 at 4 17 11 PM

How do i make a custom language?

I realise it's not an issue.

I am trying to make a custom language. how would i go about doing that?

Commenting and making Mode() available would be really helpful.,

RangeError when setting single letter to CodeController

When you set single letter to CodeController, it throws this error:

[ERROR:flutter/lib/ui/ui_dart_state.cc(209)] Unhandled Exception: RangeError (index): Invalid value: Only valid value is 0: -1
#0      _StringBase.[] (dart:core-patch/string_patch.dart:260:41)
#1      CodeController.value=
package:code_text_field/src/code_controller.dart:166
#2      TextEditingController.text=
package:flutter/…/widgets/editable_text.dart:136
#3      _MyAppState.initState.<anonymous closure>
package:class_to_record/maina.dart:21
#4      new Future.delayed.<anonymous closure> (dart:async/future.dart:393:39)
#5      _rootRun (dart:async/zone.dart:1420:47)
#6      _CustomZone.run (dart:async/zone.dart:1328:19)
#7      _CustomZone.runGuarded (dart:async/zone.dart:1236:7)
#8      _CustomZone.bindCallbackGuarded.<anonymous closure> (dart:async/zone.dart:1276:23)
#9      _rootRun (dart:async/zone.dart:1428:13)
#10     _CustomZone.run (dart:async/zone.dart:1328:19)
#11     _CustomZone.bindCallback.<anonymous closure> (dart:async/zone.dart:1260:23)
#12     Timer._createTimer.<anonymous closure> (dart:async-patch/timer_patch.dart:18:15)
#13     _Timer._runTimers (dart:isolate-patch/timer_impl.dart:395:19)
#14     _Timer._handleMessage (dart:isolate-patch/timer_impl.dart:426:5)
#15     _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:192:12)

This doesn't happen when you set either 0 or more than 1.

Repro:

import 'package:code_text_field/code_text_field.dart';
import 'package:flutter/material.dart';

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

class MyApp extends StatefulWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  final _controller = CodeController();

  @override
  void initState() {
    super.initState();
    _controller.text = 'x';
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: CodeField(
          controller: _controller,
        ),
      ),
    );
  }
}

EDIT: something weird is happening if you "redirect" one field to another.
If you do this:

late final _controller1 = CodeController(onChange: (t) => _controller2.text = t);
final _controller2 = CodeController();

Column(
  children: [
    CodeField(controller: _controller1),
    CodeField(controller: _controller2),
  ],
),

If you start writing in the first field, it doesn't write the first letter (throws error), after you press another, it writes both. Then it again doesn't write (throws error), then again writes both.

Sub languages support

The highlight package detects when more than one languages are in a text and treat them accordingly.
Like the xml language switch to javascript whenever it detects a tag of script. But this somehow doesn't work with this package.
I tried looking into your code it might be related to how you are registering the languages.

Make CodeController.language mutable

Can we make language mutable after the controller is created? I need to switch language in my UI. This currently requires re-creating the controller.

Publish new version to include lineNumbers functionality

First off, great library! Thanks for writing & maintaining it!

I'd like to use the lineNumbers visibility toggle you added into CodeField but I noticed the package published on pub.dev is a little outdated (most recent version was published around a year ago).

Would you be able to publish a new version with the most recent changes?

TextField shrinks to one line on click

There is a bug with current master.

  1. Run the example from this package in Chrome. The window shows as usual:
    image

  2. Click inside the text field. The field shrinks to one line:
    image

This is not happening with v1.0.2.

I nailed it down to this line:

keyboardType: TextInputType.visiblePassword,

Comment it out, and it works as before.

The change was introduced in https://github.com/BertrandBev/code_field/pull/36/files
@ihorkozar what was the motivation for it?

Delete CodeController.onChange

CodeController.onChange can be replaced with

controller.addListener(() {
  final text = controller.rawText;
});

If we delete onChange(), the benefits are:

  • User code is less messy. If they use both ways to listen to changes, their code is hard to maintain.
  • Less code for us to maintain.
  • Following Flutter convention. Controllers are listened to, and widgets have onChanged because they are disposable and so cannot be listened to. Both TextField and CodeField have one.
  • More consistent API. CodeField.onChanged is called with dots with webSpaceFix while CodeController.onChange is called with spaces.

@BertrandBev still you added onChange after rawText, so I wander what was the motivation for it. Are you OK with deleting it in the next breaking release?

update readme

I think the readme is out of date, this code import 'package:code_text_field/code_field.dart'; should be modified to import 'package:code_text_field/code_text_field.dart';

[Enhancement request]: Exposing cursor position changes in callback

It would be very useful to me to understand where a user's cursor is, both location in the content, and the pixel position, to enable giving syntax completion popups to the user.

It would also be useful to move the user's cursor, for example navigating to an error in the code being edited.

Any pointers on how to get started on implementing these features gladly accepted. Thanks!

Can't build for macOS

I've run flutter clean but that didn't help.

Logs:

../../../flutter/.pub-cache/hosted/pub.dartlang.org/code_text_field-1.0.0-9/lib/src/code_field.dart:16:12: Error: The method 'LineNumberController.buildTextSpan' has fewer named arguments than those of overridden method 'TextEditingController.buildTextSpan'.
  TextSpan buildTextSpan({TextStyle? style, bool? withComposing}) {
           ^
../../../flutter/packages/flutter/lib/src/widgets/editable_text.dart:192:12: Context: This is the overridden method ('buildTextSpan').
  TextSpan buildTextSpan({required BuildContext context, TextStyle? style , required bool withComposing}) {
           ^
../../../flutter/.pub-cache/hosted/pub.dartlang.org/code_text_field-1.0.0-9/lib/src/code_field.dart:16:12: Error: The method 'LineNumberController.buildTextSpan' doesn't have the named parameter 'context' of overridden method 'TextEditingController.buildTextSpan'.
  TextSpan buildTextSpan({TextStyle? style, bool? withComposing}) {
           ^
../../../flutter/packages/flutter/lib/src/widgets/editable_text.dart:192:12: Context: This is the overridden method ('buildTextSpan').
  TextSpan buildTextSpan({required BuildContext context, TextStyle? style , required bool withComposing}) {
           ^
../../../flutter/.pub-cache/hosted/pub.dartlang.org/code_text_field-1.0.0-9/lib/src/code_controller.dart:210:12: Error: The method 'CodeController.buildTextSpan' has fewer named arguments than those of overridden method 'TextEditingController.buildTextSpan'.
  TextSpan buildTextSpan({TextStyle? style, bool? withComposing}) {
           ^
../../../flutter/packages/flutter/lib/src/widgets/editable_text.dart:192:12: Context: This is the overridden method ('buildTextSpan').
  TextSpan buildTextSpan({required BuildContext context, TextStyle? style , required bool withComposing}) {
           ^
../../../flutter/.pub-cache/hosted/pub.dartlang.org/code_text_field-1.0.0-9/lib/src/code_controller.dart:210:12: Error: The method 'CodeController.buildTextSpan' doesn't have the named parameter 'context' of overridden method 'TextEditingController.buildTextSpan'.
  TextSpan buildTextSpan({TextStyle? style, bool? withComposing}) {
           ^
../../../flutter/packages/flutter/lib/src/widgets/editable_text.dart:192:12: Context: This is the overridden method ('buildTextSpan').
  TextSpan buildTextSpan({required BuildContext context, TextStyle? style , required bool withComposing}) {
           ^

Command PhaseScriptExecution failed with a nonzero exit code
note: Using new build system
note: Building targets in parallel
note: Planning build
note: Analyzing workspace
note: Constructing build description
note: Build preparation complete
** BUILD FAILED **

Exception: Build process failed

Cluttering highlight with duplicate languages

Currently CodeController registers languages with highlight using a random string. When multiple controllers are created with the same language, this same language is registered in highlight under multiple generated IDs.

Can we avoid this? Why don't we use mode.hashCode.toString() or something similar for ID when registering languages?

Remove pubspec.lock from package and example

pubspec.lock should not be in libraries because it is ignored when it is included in an app.

pubspec.lock should not be in example because for app that simple it brings no benefits but it is one more thing to maintain and merge.

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.