Sunday, March 9, 2008

Tweak Gedit into a Programmers IDE

Gedit is a simple text editing program that is installed with many Linux distributions. At first glance it does not appear to have advanced features needed for an IDE, but with a little bit of configuration it can be turned into a really nice code editor supporting Java, Python, C, C++, HTML and many other languages. A sample screen shot of fully configured Gedit is shown.

Before we begin, here is a quick list of Gedit's features:

  • Tabbed file view
  • Syntax highlighting
  • Inline command shell
  • Template code insertion
  • Basic tag browser
  • Session manager (save/restore windows)
  • Spell checking
  • Bracket matching
  • Auto indenting
Unfortunately, there are still a few features missing others might require in an IDE:
  • Syntax completion
  • Integrated debugging environment
  • Side-by-side window view (i.e. split windows)
  • Graphical syntax color configuration (text only configuration at this point)
Hopefully, the list above is manageable and may shrink in the future. So lets begin with the configuration.

Basic Setup:
The first step is to enable some built-in features of Gedit disabled by default. Under Edit->Preferences, configure the View and Edit tabs as shown:

The next tab allows you to set the default font and color scheme. For now, check the box to use Monospace 10 font by default. We will come back to the "Color Scheme" options later.

Plugin Setup:
The rest of changes in Gedit will be enabled by plug-ins. The default Gedit Plugin Page is a great place to look for new and 3rd party plugins. Feel free to browse it later, but start with the following ones for now.

Bracket Completion (Optional)
Some programmers might like this feature, but usually I leave this one disabled.

Code comment
This is a really handy feature to comment/un-comment code quickly. Just us Ctrl-M or Ctrl-Shift-M to effectively enable or disable code. It also works on multiple lines.

Color Picker
For doing HTML programming or any document that needs color hex values, this plugin will bring up a color chooser widget, and insert the hex value after you hit 'ok'. Document Statistics I don't use this one too often, but can be handy to see your current line counts and file size.

Embedded Terminal
Provides you with a terminal window at the bottom of the screen. This is really great for executing your code or looking up man pages quickly.


File Browser Pane
One of the nicer features, the File Browser will show a tree on the left hand side, so you can quickly open other files in your project.


Indent Lines
Enables Tab (indenet) and Shift-Tab (remove indent) features on selected text. Enough said.

Join/Split Lines
The join split feature can come in handy when writing code comments. Just write the entire comment on a single line, and it Ctrl-Shift-J to split the line. It will also indent if your selection begins mid-line. Also good for dealing with files that are missing line breaks.

Modelines
For file that have embedded modelines at the end, this lets Gedit read those value and adjust accordingly. Great if you switch between multiple editors.

Session Saver
Another must have, this lets you build up project sessions, saving which files are opened. The next time you run Gedit, load your session and all your files are back to where they were.

Smart Spaces
This is a must have to allow the Backspace key to treat expanded tabs as a single tab character. Otherwise, you will have to delete every space of a "Tab".

Snippets
Auto text completion tool. If you learn to use this, it will make your life much easier. Insertions can be done with a keyword-TAB or a keypress command. The defaults install comes with a number of built-in examples. And you can add as many snippets as you want, all divided by language.


Spell Checker
Includes auto-spell check feature, but unfortunately does not restrict checking to just comments. Maybe it can be fixed soon.

Symbol Browser
This plugin creates a window on the left hand side that provides a quick way to jump between functions an classes of your code. Unfortunately there is no in-editor symbol browser yet.


Tag List
When modifying HTML or XML files, this plugin provides a tag browser on the left hand side.


Syntax Color Themes:
Gedit provides a few built-in color themes, but there is no way to modify the installed color themes other than directly editing the theme files. The current theme files are stored in /usr/share/gtksourceview-2.0/styles. You can use these to create your own theme files. Once you have your theme file, you can import it into Gedit using the option Preferences->Fonts & Colors->Add.

If you want to find a specific element to change the color of, your best bet is to look into /usr/share/gtksourceview-2.0/language-specs/*.lang

A sample syntax file is shown.
<?xml version="1.0" encoding="UTF-8"?>

<style-scheme id="custom" _name="Custom" version="1.0">
  <_description>Custom color scheme</_description>

  <!-- Palette -->
  <color name="blue"       value="#0000FF"/>
  <color name="magenta"    value="#f066f0"/>
  <color name="violet"     value="#9587e9"/>
  <color name="cyan"       value="#00fbff"/>
  <color name="green"      value="#00ff00"/>
  <color name="bordeaux"   value="#d47575"/>
  <color name="orange"     value="#ffa500"/>
  <color name="red"        value="#FF0000"/>
  <color name="yellow"     value="#f1f16e"/>
  <color name="mustard"    value="#b8b86f"/>
  <color name="purple"     value="#bb41ea"/>
  <color name="grey3"      value="#353535"/> 
  <color name="grey4"      value="#4d4d4d"/>
  <color name="grey7"      value="#7f7f7f"/>
  <color name="grey9"      value="#969696"/>
  <color name="greyA"      value="#a7a7a7"/>
  <color name="greyB"      value="#bfbfbf"/>
  <color name="greyE"      value="#e5e5e5"/>

  <!-- Global Settings -->
  <style name="text"                        foreground="#white" background="#black"/>
  <style name="selection"                   background="greyB"/>
  <style name="cursor"                      foreground="#white"/>
  <style name="current-line"                foreground="green" background="grey3"/>
  <style name="line-numbers"                foreground="green" background="grey3"/>

  <!-- Bracket Matching -->
  <style name="bracket-match"               foreground="green" background="#black" bold="true"/>
  <style name="bracket-mismatch"            foreground="red"   background="#black" bold="true"/>

  <!-- Search Matching -->
  <style name="search-match"                foreground="red"   background="mustard" bold="true"/>  
  
  <!-- Comments -->
  <style name="def:comment"                 foreground="greyA" bold="false"/>
  <style name="def:shebang"                 foreground="cyan" bold="false"/>
  <style name="def:doc-comment-element"     italic="true"/>

  <!-- Constants -->
  <style name="def:constant"                foreground="red"/>
  <style name="def:special-constant"        foreground="red"/>
  <style name="def:special-char"            foreground="violet"/>
  <style name="def:decimal"                 foreground="orange"/>
  <style name="def:base-n-integer"          foreground="orange"/>
  <style name="def:floating-point"          foreground="orange"/>
  <style name="def:complex"                 foreground="orange"/>
  <style name="def:character"               foreground="cyan"/>
  <style name="def:string"                  foreground="bordeaux"/>

  <!-- Identifiers -->
  <style name="def:identifier"              foreground="cyan"/>
  <style name="def:function"                foreground="green"/>
  <style name="def:keyword"                 foreground="yellow"/>
  <style name="def:builtin"                 foreground="red"/>

  <!-- Statements -->
  <style name="def:statement"               foreground="yellow" bold="true"/>

  <!-- Types -->
  <style name="def:type"                    foreground="green" bold="true"/>
  <style name="def:boolean"                 foreground="green" bold="true"/>

  <!-- Others -->
  <style name="def:preprocessor"            foreground="magenta"/>
  <style name="def:error"                   background="red" bold="true"/>
  <style name="def:note"                    foreground="blue" background="yellow" bold="true"/>
  <style name="def:underlined"              italic="true" underline="true"/>

  <!-- Language specific styles -->
  <style name="diff:added-line"             foreground="#008B8B"/>
  <style name="diff:removed-line"           foreground="#6A5ACD"/>
  <style name="diff:changed-line"           use-style="def:preprocessor"/>
  <style name="diff:special-case"           use-style="def:constant"/>
  <style name="diff:location"               use-style="def:statement"/>
  <style name="diff:diff-file"              use-style="def:type"/>

  <style name="xml:tags"                    foreground="cyan"/>
  <style name="xml:attribute-name"          foreground="violet"/>
  <style name="xml:namespace"               foreground="green" bold="true"/>

  <style name="js:object"                   foreground="#2E8B57" bold="true"/>
  <style name="js:constructors"             foreground="#008B8B"/>

  <style name="latex:display-math"          foreground="#6A5ACD"/>
  <style name="latex:command"               foreground="#2E8B57" bold="true"/>
  <style name="latex:include"               use-style="def:preprocessor"/>

  <style name="sh:variable1"                foreground="#6A5ACD"/>
  <style name="sh:variable2"                foreground="#008B8B"/>

  <!-- legacy styles for old lang files -->
  <style name="Others"                      foreground="#2E8B57" bold="true"/>
  <style name="Others 2"                    foreground="#008B8B"/>
  <style name="Others 3"                    foreground="#6A5ACD"/>

<!--  <style name="python:string-conversion"    use-style="def:error"/>-->
<!--  <style name="python:module-handler"       foreground="magenta"/>-->
<!--  <style name="python:special-variable"     use-style="def:identifier"/>-->
<!--  <style name="python:builtin-constant"     use-style="def:constant"/>-->
<!--  <style name="python:builtin-object"       use-style="def:type"/>-->
<!--  <style name="python:builtin-function"     use-style="def:function"/>-->
<!--  <style name="python:boolean"              use-style="def:type"/>-->

</style-scheme>
.... Read more!

Thursday, February 21, 2008

Modify Ctrl-Alt-Del Keyboard Shortcut in Ubuntu

The Ubuntu desktop has a simple GUI to modify keyboard shortcuts, but I noticed that any changes to the Ctrl-Alt-Del key combination would not work. The problem was that no matter where I assigned the Ctrl-Alt-Del shortcut, it would always open the "Logout" menu. The workaround for this bug is typed out in this post. 1. Make sure to disable the "Log out" action from the Keyboard Shortcuts editor (System->Preferences->Keyboard Shortcuts), by highlighting the line and pressing the "Backspace" key. 2. Open the Configuration Editor (System Tools->Configuration Editor), and disable the metacity Ctrl-Alt-Del binding under /apps/metacity/global_keybindings. Do this by right-clicking the key with the Ctrl-Alt-Del binding (i.e "run_command_1") and selecting "Unset Key" 3. In the same window, go to the next folder /apps/metacity/keybinding_commands. Select the matching command from the previous step (i.e. "command_1") and unset the key in the same manor as step 2. Close the Configuration Editor. 4. Finally, go back to the Keyboard Shortcuts app, and now select the new action for Ctrl-Alt-Del. Everything should work as expected now. .... Read more!

Saturday, February 9, 2008

Countdown Alarm

Recently I was looking for a "countdown alarm clock" in Linux and decided to write a Bash script to do the job. The goal was to allow the user to enter a target date and time, then display a clock with the remaining time. An example of the output is below.

Features:

  • Remaining time stays at top left corner of the screen and continuously updates.
  • Update!: Output time inserted in Xterm title bar.
  • Target time can be specified using natural language string. (i.e. Feb 21 5PM 2010)
  • Remaining time displayed in years, months, days, hours, minutes, and seconds remaining.
  • Year, month, and day output is optional depending on the length of the remaining time.
Implementation:

It might seem complicated to do this, but the Unix 'date' utility handles almost all of the program logic for us. For example, to convert a generic date string into the number of seconds from Jan 1st, 1970:
date -d "DATE STRING" +%s

The date command can then easily do the reverse operation, using the output of the first command, where "SECONDS" is number of seconds from Jan 1st, 1970:
date -d @SECONDS

Some screen drawing tricks were accomplished with special terminal escape commands. These are used to move the cursor out of the way, and clear the line before each update.

Code: countdown.sh
#!/bin/bash
BLINK=1
INPUT_DATE=$@
STOP=`date -d "$INPUT_DATE" +%s`
[ $? == 0 ] || exit -1

function print_time
{
   echo -ne "\033]0;$@\007"   # update window title
   echo -ne "$@"              # update terminal
}

clear

while [ 1 ]; do
   NOW=`date +%s`
   TIME=''
   
   if [ $STOP -gt $NOW ]; then
      REMAIN=$[ $STOP - $NOW ]

      YEAR=`date -u -d @$REMAIN +%Y`
      YEAR=$[ $YEAR - 1970 ]
      [ $YEAR -gt 0 ] && TIME="${TIME}$YEAR year"
      [ $YEAR -gt 1 ] && TIME="${TIME}s"
      [ $YEAR -gt 0 ] && TIME="${TIME}, "

      MONTH=`date -u -d @$REMAIN +%_m`
      MONTH=$[ $MONTH - 1 ]
      [ $MONTH -gt 0 ] && TIME="${TIME}$MONTH month"
      [ $MONTH -gt 1 ] && TIME="${TIME}s"
      [ $MONTH -gt 0 ] && TIME="${TIME}, "

      DAY=`date -u -d @$REMAIN +%_d`
      DAY=$[ $DAY - 1 ]
      [ $DAY -gt 0 ] && TIME="${TIME}$DAY day"
      [ $DAY -gt 1 ] && TIME="${TIME}s"
      [ $DAY -gt 0 ] && TIME="${TIME}, "

      TIME="${TIME}`date -u -d @$REMAIN +%T`"
      print_time $TIME
   else
      [ $BLINK -eq 1 ] && print_time "00:00:00"
      [ $BLINK -eq 0 ] && print_time ""
      BLINK=$[ $BLINK ^ 1 ]
   fi

   echo -ne "\e[s"            # save cursor position
   echo -ne "\e[1000;1000f"   # move cursor to bottom right of screen

   sleep 0.5 
   echo -ne "\e[u"   # restore cursor position
   echo -ne "\r"     # move cursor to start of line
   echo -ne "\e[0K"  # clear line
done

.... Read more!