New Component: streamlit-code-editor, a react-ace code editor customized to fit with streamlit with some extra goodies added on top

Hi,
I have created a code editor component based on react-ace but whose appearance is customized to fit with Streamlit’s look. I also added the ability/option to add a customizable info bar, menu bar, and customizable buttons.

I am relatively new to Streamlit and was well into this project when I learned of the already existing Ace Editor component (okld’s Ace Editor). However, I believe there are enough differences and additions to warrant sharing.

Warning: This project started as mostly an excuse to learn React (and I got hooked real quick :grin: ) and thus I do not consider it production ready.

Installation:

pip install streamlit_code_editor

Resources:

Demo reel:
basic settings

demo-pt1

adding info bar and custom buttons

demo-pt2

5 Likes

Hi @bouzidanas

Thanks for creating this new code editor component!

Best regards,
Chanin

1 Like

Hey again,

I just want to add some updates for those who have started using this component or are planning to.

First, streamlit-code-editor has moved to a new location since version 0.0.9. Check it out here:

Second, if you look at the gifs in top post here, you may notice that the editor flashes when any of the settings in the inputs above it are changed. This happens for two reasons:

  1. The editor doesnt have a fixed key set (using key= argument) and so it is replaced by a newly created one each time its arguments change or that part of the page is rerun. This results in the collapsing expanding effect seen in the gif.

  2. The custom themes used by this component are loaded dynamically which results in a delay compared to default theme loaded instantly. This results in the color change that is most noticeable when applying the dark custom theme.

I am happy to say that these issues have been resolve (as far as I can tell). The custom themes are loaded instantly.

The first issue should be resolved by using a fixed key and it is, but using a fixed key removes the ability to update/change/reset the contents of the editor programmatically. This was intentional to prevent loss of the latest edits made by the user. However, the edits arent really lost as they are stored in the edit history so a simple undo will restore anything lost which is what encouraged me to add the ability to force the code editor to respond to changed inputs when key is fixed. To do this, you set the newly added argument, allow_reset=True (defaults to False).

There are other things you will find in the latest version like improved scrollbar behavior and a new bindKey: {"win": "key-combo", "mac": "key-combo"} option for the custom buttons that allows you to set a keyboard shortcut to trigger a button.

More great things are planned so stay tuned!

how to get only selected code in response dict

The features that you could use to do that are not yet built into the component. I recommend you make a feature request (issue) on the github and I will get around to it when I can.

Hey again,

Just want to let you know that I have added a new command called returnSelection which will return the selected text in the response dictionary.

You can add a button or a shortcut to trigger the response. For more on adding a button that triggers this new command, see the Advanced Usage section of the docs.

For example,

import json
import streamlit as st
from code_editor import code_editor

# code editor config variables
height = [19, 22]
language="python"
theme="default"
shortcuts="vscode"
focus=False
wrap=True
editor_btns = [{
    "name": "Run",
    "feather": "Play",
    "primary": true,
    "hasText": true,
    "showWithIcon": true,
    "commands": ["returnSelection"],
    "style": {"bottom": "0.44rem", "right": "0.4rem"}
  }]
sample_python_code = '''# This is some sample code
a=2
if a > 1:
    print("The value is greater than 1")
'''

# code editor
response_dict = code_editor(sample_python_code,  height = height, lang=language, theme=theme, shortcuts=shortcuts, focus=focus, buttons=editor_btns, options={"wrap": wrap})

# show response dict
if len(response_dict['id']) != 0 and ( response_dict['type'] == "selection" or response_dict['type'] == "submit" ):
    st.write(response_dict)

This new command exists in the newest version (currently 0.1.12) on npm.

2 Likes

Hello, great work!
I’ve gone through the documentation yet I haven’t figured out how to enable interpretation within the code sample (sample_python_code). In your example the string is fixed, however, can it be adjusted by the user within the application and received by a variable (sample_python_code)?

If I understand you correctly, yes. Perhaps it is not explained very well in the docs (I will try to improve the docs more in the future), but the content of the code editor is editable and changeable and to get the changed code back (as the response/return value in streamlit), you have to trigger a response command. There are two ways to do so, by adding a button that calls the response command when clicked, or by setting a keyboard shortcut.

By default, code editor works like st.text_area. For the user to ‘submit’ the text in the text area, they have to press Ctrl + Enter when they are done changing the text. Same thing with code editor. The default behavior is that the user needs to press Ctrl + Enter keyboard shortcut after they are done changing the code in the editor and they want the changes seen by the app. Behind the scenes, the Ctrl + Enter keyboard shortcut triggers the submit command which is one of the response commands that can be used to send back stuff to the streamlit app.

You can test this out in the demo. Change the code in the editor and then press Ctrl + Enter. To see it working with a button, open the Components expander and check the custom buttons checkbox. Then when you hover over the editor, the custom buttons will appear. Fyi, the Run button at the bottom triggers the submit command and so should do the same thing as the keyboard shortcut when you click it.

Now, what happens when one of these response commands are triggered? Well, what happens is that the code_editor function in the streamlit script returns a dictionary containing the code among other things like response type and response id and cursor position when response was triggered.

So how would I update the code without using ctrl + enter:

code = code_editor(“”)

# Button to execute code
if st.button("Run Code"):
    execute_code(code['text'])

Hello, this may be a late response however I’d like to pitch in on how to capture the selected code parameter to perform actions upon. I’d also love to see line numbering added to this code editor. @bouzidanas

import json
import streamlit as st
from code_editor import code_editor

# code editor config variables
height = [19, 22]
language="python"
theme="default"
shortcuts="vscode"
focus=False
wrap=True
editor_btns = [{
    "name": "Run",
    "feather": "Play",
    "primary": True,
    "hasText": True,
    "showWithIcon": True,
    "commands": ["submit"],
    "style": {"bottom": "0.44rem", "right": "0.4rem"}
  }]
sample_python_code = '''# This is some sample code
a=2
if a > 1:
    print("The value is greater than 1")
'''

# code editor
response_dict = code_editor(sample_python_code,  height = height, lang=language, theme=theme, shortcuts=shortcuts, focus=focus, buttons=editor_btns, options={"wrap": wrap})

# show response dict
if len(response_dict['id']) != 0 and ( response_dict['type'] == "selection" or response_dict['type'] == "submit" ):
    # Capture the text part
    code_text = response_dict['text']
    st.code(code_text, language='python') #Captured the code parameter.

Hi @abd_kmm,

Line numbering isnt turned on by default but you can turn it on with one of the config options so in the code_editor function just add options={"wrap": True, "showLineNumbers": True}

Hello @bouzidanas, that didn’t work on my side. Maybe I have done something wrong here?

import json
import streamlit as st
from code_editor import code_editor

# code editor config variables
height = [19, 22]
language="python"
theme="default"
shortcuts="vscode"
focus=False
wrap=True
editor_btns = [{
    "name": "Run",
    "feather": "Play",
    "primary": True,
    "hasText": True,
    "showWithIcon": True,
    "commands": ["submit"],
    "style": {"bottom": "0.44rem", "right": "0.4rem"}
  }]
sample_python_code = '''# This is some sample code
a=2
if a > 1:
    print("The value is greater than 1")
'''

# code editor
response_dict = code_editor(sample_python_code,  height = height, lang=language, theme=theme, shortcuts=shortcuts, focus=focus, buttons=editor_btns, options={"wrap": True, "showLineNumber": True})

# show response dict
if len(response_dict['id']) != 0 and ( response_dict['type'] == "selection" or response_dict['type'] == "submit" ):
    # Capture the text part
    code_text = response_dict['text']
    st.code(code_text, language='python') #Captured the code parameter.```

Appologies! There is a typo in my previous response to you. It is showLineNumbers plural instead of showLineNumber . I will correct my previous comment! The list of options can be found here

1 Like

No worries! Thanks, now this makes it look better. I appreciate it!