Skip to content
David Gonzalez edited this page Feb 9, 2016 · 27 revisions

Ace code editor

What is the Ace code editor, and where can I learn more about it?

Ace is web-based code editor that can be easily embedded in html pages as a JavaScript library. Out of the shelf it offers several features such as syntax highlighting, auto-format, drag and drop, code folding and more. Currently, it is capable of doing live syntax check in JS/CoffeeScript/CSS/Xquery. Also, it provides an API to extend its functionalities and add custom features. It is widely used in the industry, with the most notorious use being the code editor of the web-based IDE, Cloud9.

The following diagram provides an overview of Ace components. Please check other questions to learn how to add overlays via the Virtual Renderer, capture edit and user events with the Edit Session.

You can learn more about it here https://ace.c9.io/#api=&nav=about. For more details of its structure and API, check here https://ace.c9.io/#nav=api. For trouble-shooting and lore check the “ace-editor” tag in Stackoverflow http://stackoverflow.com/questions/tagged/ace-editor.

How do I embed it in my page?

  1. Add the library from CDNJS:

    <script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.2.3/ace.js" type="text/javascript" charset="utf-8"></script>
  2. Add your section on your web page:

    function foo(items) { var x = "All this is syntax highlighted"; return x; }
  3. and initiate the editor session:

    <script> var editor = ace.edit("editor"); editor.setTheme("ace/theme/monokai"); editor.getSession().setMode("ace/mode/javascript"); </script>

How do I add markers (e.g. breakpoints) to the gutter?

For custom items in the gutter use editor's method addGutterDecoration(Number row, String className). This example uses the built-in breakpoint logic. Capture the mouse down event in the editor, resolve the line and add or remove the breakpoint:

	editor.renderer.setShowGutter(true);		
	editor.on("guttermousedown", function(e){ 
		var target = e.domEvent.target; 
		
		if (target.className.indexOf("ace_gutter-cell") == -1){ 
			return;
		}
		if (!editor.isFocused()){ 
			return;
		}
		if (e.clientX > 25 + target.getBoundingClientRect().left){ 
			return; 
		}
		var row = e.getDocumentPosition().row;
		var breakpointsArray = e.editor.session.getBreakpoints();
		if(!(row in breakpointsArray)){
			e.editor.session.setBreakpoint(row);
		}else{
			e.editor.session.clearBreakpoint(row);
		}
		e.stop(); 
	}); 
	editor.session.on("changeBreakpoint", function(e){
		// captures set and clear breakpoint events
	});

This is the style used for the breakpoint:

	.ace_gutter-cell.ace_breakpoint{ 
		border-radius: 20px 0px 0px 20px; 
		box-shadow: 0px 0px 1px 1px red inset; 
	}

Find more info here

I want to build a visualization that overlays visual shapes on top of the code and I want it to move smoothly when the code scrolls. What's the best way to do that?

The best way to add visualizations in the editor is adding anchors to the Document object of the Edit Session. Then using the API to communicate the Virtual Renderer module via the Editor module( API’s entry class).

The following snippet shows how to add an icon that moves with the scroller and points out to the last selection.

  1. Let's define the overlay in the body of the html page (or where you need it).

             <canvas id ="overlay" width="20" height="20"> </canvas>
    

In this case is a canvas that we force to be upfront with the z-index via a CSS style.

	#overlay{
		position:absolute;
		z-index: 100;		
	}
  1. Let's implement how that overlay is drawn. We receive the position where is going to be drawn as a parameter (position.pageX and position.pageY).

     function updateOverlay(position){
     var div =document.getElementById("overlay");
     div.style.left = position.pageX + 'px';
     div.style.top = position.pageY + 'px';
     // Check the element is in the DOM and the browser supports canvas
     if(div.getContext) {
     	// Initaliase a 2-dimensional drawing context
     	var context = div.getContext('2d');
     	//Canvas commands go here
     	// Create the yellow circle
     	context.strokeStyle = "#000000";
     	context.fillStyle = "#FFFF00";
     	context.beginPath();
     	context.arc(10,10,5,0,Math.PI*2,true);
     	context.closePath();
     	context.stroke();
     	context.fill();
    

    }

  2. Now, we add an anchor to the document. An anchor will follow Ace's changes to the document, so we only have to worry about the events and not to calculate the position. For these snippets, let's assume the editor have been instantiated. For that, we need to activate the scrolling animations.

             // adding overlays
     editor.renderer.setAnimatedScroll(true);
    

Then, we get the document and add the anchor to a default position. The default depends on the logic you want. For this example, we are adding an overlay to the current text selection.

	var aceDocument = editor.getSession().getDocument();
	var anchor = aceDocument.createAnchor( 0, 0);
	anchor.on("change", function(e){
			updateOverlay(editor.renderer.textToScreenCoordinates(anchor.getPosition())); 
	});
	updateOverlay(editor.renderer.textToScreenCoordinates(anchor.getPosition())); 

We should catch the scrolling events to avoid that the overlay stays visible when the anchor is not.

	editor.getSession().on("changeScrollLeft", function(scrollLeft){
updateOverlay(editor.renderer.textToScreenCoordinates(anchor.getPosition())); 
});

editor.getSession().on("changeScrollTop", function(scrollTop){
updateOverlay(editor.renderer.textToScreenCoordinates(anchor.getPosition())); 
});

And for the example, catch the selection events.

	editor.getSession().selection.on('changeSelection', function(e) {
			var range = editor.getSelectionRange();
			if(range){
			anchor.setPosition(range.end.row, range.end.column, false);
			}
	});

Information about Ace’s structure can be found here https://ace.c9.io/#nav=api.

I want to create a popup that comes up whenever the user hovers over a piece of code. What's the best way to do that?

Use the API for the event listener.

I want to get an event whenever the selection changes, either by mouse click or by keyboard input. Can I do that?

Not directly, you can get the selection event and then specify the type of input. These events are handled by the Edit Session object. You can get it by using the following command: editor.getSession().selection.on('changeSelection', function(e) { });

Clone this wiki locally