Posts Tagged: Programmer’s Notepad


27
Oct 07

Programmer’s Notepad – Calculator Part 2

This time we’re going to use a PyPN script to evaluate maths expressions. We’re cheating a little, because we’re just going to ask python to evaluate a string and get a number back out.

import pn, scintilla

@script("Calculator")
def DoMaths():
    s = scintilla.Scintilla(pn.CurrentDoc())

    if s.SelectionEnd - s.SelectionStart < 1:
        return

    sel = s.SelText

    i = eval(sel)
    if type(i) in [int, float, complex]:
        pn.AddOutput(str(i))

To use this, simply select an expression like “5+5″ in the editor, run the script, and the output window will contain the evaluation of the expression.

This script is very simple, and in fact could be generalised to a python expression evaluator, but it serves the intended purpose well. It could also be adapted to make sure that expressions are of the form "exp=" and then put the result after the = sign, or perhaps to replace the selected expression with the result. These changes are left as exercises for the reader!


26
Oct 07

Programmer’s Notepad – a Calculator?!

One of the recent feature requests for Programmer’s Notepad was to add the ability in PN to perform basic numeric conversions, e.g. decimal to hex. Also the ability to evaluate simple mathematical expressions like 2+3=.

With the PyPN extension this is very easy, and the required features can even be bound to keyboard shortcuts.

Number Conversions:

The first thing we might want to do is see hex, decimal, octal or even binary representations of a selected number. The following script plus helper functions does this for decimal or hex selections:

import pn, scintilla 

def hex2dec(s):
    """return the integer value of a hexadecimal string s"""
    return int(s, 16) 

def Denary2Binary(n):
    """convert denary integer n to binary string bStr"""
    bStr = ''
    if n < 0:
        raise ValueError, "must be a positive integer"
    if n == 0:
        return '0'
    while n > 0:
        bStr = str(n % 2) + bStr
        n = n >> 1
    return bStr 

@script("ConvertNumber")
def ConvertNumber():
    s = scintilla.Scintilla(pn.CurrentDoc())
    if s.SelectionEnd - s.SelectionStart < 1:
        return sel = s.SelText
    if sel.find('0x') != -1:
        sel = sel.replace("0x", "")
        sel = hex2dec(sel)
    else:
        sel = int(sel)
    pn.AddOutput("Dec: %d\n" % sel)
    pn.AddOutput("Hex: 0x%X\n" % sel)
    pn.AddOutput("Oct: %o\n" % sel)
    pn.AddOutput("Bin: %s" % Denary2Binary(sel))

In the next post we’ll look at evaluating simple math expressions.


17
Apr 07

Build 667 and PyPN 0.5

A new development build is available on Sourceforge, get it here:

Download PN 2.0.7.667

Also: Zip Distribution | Portable Edition Zip

This build introduces the global scheme management changes that have been promised for a long time. This means that (where the schemes have been updated already) you can change a single colour and have keywords, numbers, properties and the like use that colour in all schemes. It does need some schemes to be updated to work properly which is ongoing work.

Styles Options

The build also finally seperates HTML/PHP schemes from the original Hypertext and adds a PHP Script scheme for pure PHP files (i.e. ones with no <?php?>) in them.

Other changes are of more interest to extension developers. The tagging interface has been removed and a new one created within the standard extensions framework. The ctags tagger is now an extension – users should notice no difference.

There is a new extension discovery mechanism, simply run PN with the “–findexts” argument and config.xml will be updated with all found extensions.

Finally there are a couple of new extension points in the interface allowing extensions to respond to events when documents are saved and loaded (before and after respectively).

PyPN 0.5 has been released at the same time, providing compatibility with the new build along with some minor fixes and support for the new events.


10
Apr 07

Tabs to Spaces with PyPN

Want to convert your tabs to spaces and annoyed that your editor author hasn’t implemented that feature in a handy menu item yet?

Add a PyPN script to do it:

import pn
import scintilla
from pypn.decorators import script

def SetTarget(e, x, y):
	e.TargetStart = x
	e.TargetEnd = y

@script("Tabs to Spaces", "Text")
def TabsToSpaces():
	editor = scintilla.Scintilla(pn.CurrentDoc())

	tabSpaces = editor.TabWidth
	spaces = ""
	for x in range(tabSpaces):
		spaces = spaces + " "

	end = editor.Length

	SetTarget(editor, 0, end)
	editor.SearchFlags = 0
	editor.BeginUndoAction()

	pos = editor.SearchInTarget(1, "\t")

	while(pos != -1):
		l1 = editor.TargetEnd - editor.TargetStart
		editor.ReplaceTarget(tabSpaces, spaces)

		# adjust doc length
		end = end + tabSpaces - l1
		start = pos + tabSpaces

		if start >= end:
			pos = -1
		else:
			SetTarget(editor, start, end)
			pos = editor.SearchInTarget(1, "\t")

	editor.EndUndoAction()

27
Mar 07

PyPN: Upload to FTP

Over in the forums, MurphyMc shows a sample bit of script that will upload your current file to FTP using Python via a PyPN script. It currently hard-codes site/user/pass etc. but these could easily be retrieved from elsewhere (potentially even project properties in the future).

Save To FTP Script

It’s easy to imagine how this could be extended in lots of directions, for example a script could retrieve a file from FTP, store it in a temporary location and then re-upload when the user is finished. That’s FTP integration done, what next!

Obviously I understand that many requests are for a fully-integrated FTP browser/editor, but this example really shows what can be achieved with the scripting integration.


27
Mar 07

PyPN: Validate Your Xml

Have you tried playing with PyPN and PN’s scripts system yet? If not, then perhaps you should. A large number of requests on PN’s Feature Requests tracker could be implemented as scripts. Some perhaps not so elegantly as if they were built in, others perfectly.

To start looking at ways that PyPN enhances Programmer’s Notepad, let’s look at a very early feature request: Validate XML.

Here is a simple PyPN script that does just this, adding a command to the scripts window called Validate in the XML group. This can, of course, be mapped to a keyboard shortcut.

The script simply runs the contents of your document through expat. When your Xml is valid no output is printed, where there’s an error the output window will show you the details.

To use this code, just drop it in a file called something like pnxml.py in the scripts directory. You’ll need PyPN installed, along with Python 2.4 and the PyXml package. As of Python 2.5 expat is bundled so the extra package won’t be necessary.


import pn
import scintilla
from pypn.decorators import script
import xml.parsers.expat as expat

@script("Validate", "Xml")
def ValidateXml():
	editor = scintilla.Scintilla(pn.CurrentDoc())
	text = editor.GetText(0, editor.Length)

	parser = expat.ParserCreate()

	try:
		parser.Parse(text, True)
	except expat.ExpatError, ex:
		pn.AddOutput("Error: " + str(ex))

22
Sep 06

PN 2.0.7.610 and PyPN 0.3 Released

I’m pleased to announce that the current development build on SourceForge of PN 2 is now 2.0.7.610 which contains just minor fixes from .609 to make working with extensions better. PyPN 0.3 adds a number of features over the first two releases and also several bugfixes.

Download PN 2.0.7.610

Download PyPN 0.3

Remember you’ll need Python 2.4 installed to use PyPN.


17
Aug 06

Announcing pyPN-0.1

I finally got some time to clean up and zip up the current pyPN bits and have uploaded them to the web site:

http://www.pnotepad.org/files/pypn-0.1.zip

You will need the latest development build of PN (2.0.7.608 at the time of writing) and Python 2.4 to use this.

What is pyPN?

pyPN is the first extension for Programmer’s Notepad 2, and provides support for scripting PN using Python! You can already do a lot, but there’s also a lot of functionality yet to be exposed.

Other extensions can be provided using the same mechanism pyPN uses, see http://www.pnotepad.org/plugindoc/ for the gory C++ details (not as scary as you might think!).

Version 0.1

This is definitely beta software, so please experiment and report plenty of feedback! Extract the files into your PN folder and restart PN. If you already have a config.xml file you’ll need to merge the two files.

There will be more documentation as time goes on, but the code includes one very simple sample script showing how scripts can be built in to the scripts window. You can turn any python file or buffer into a runnable script by right-clicking and selecting “Use as Script” – this will add the window to the scripts window from where you can double-click to run.

So, some simple examples:

import pn
pn.AddOutput(“Hello!\n”)

This will add text to the output window (you’ll need to show the window first).

To work with scintilla (the text editing component) try something like this:

import pn, scintilla
s = scintilla.Scintilla(pn.CurrentDoc())
s.AppendText(6, “Hello!”)

When you make a mistake in your script at runtime the traceback will be shown in the output window (again, you need to manually show this).

Note that if you put broken scripts in the scripts directory this will currently crash PN on startup – this will  be fixed in future versions.

Finally note that you get some automatic indenting when writing Python code now, the code for this is in the init.py file. You can write indenters for other languages in a similar style. The indenting isn’t perfect, but I love it!

Let me know how you get on, and post anything that works for others to see as either a comment or on the forums!


2
Feb 06

PyPN

I’m making progress with the Python scripting system, and am getting close to releasing a new testing build that has this functionality enabled. This won’t be for the weak of heart because I suspect there will be all sorts of problems to iron out.

Adding a new python script to be run is easy, there is a scripts directory under your Programmer’s Notepad install, and any python file placed in there will be automatically loaded at run time. PN does not see every bit of code in that file as a script, instead you must register your function as a script when desired.

To do this, you use the “script” decorator:

from pypn.decorators import *
import debug

@script()
def myFirstScript():
    debug.OutputDebugString("hello world!")

This will automatically register a script called “myFirstScript” under a group of scripts called “Python”. You can also re-name your script and/or specify the name of a group of scripts to include it in:

@script("My First Script", "Tutorial")
def myFirstScript():
    debug.OutputDebugString("hello more advanced world!")

Scripts appear in a new Scripts docking window in PN with a tree. Currently the only way to run a script is to double-click on it but you will eventually be able to assign shortcuts to them.

Of course, having started with scripts, you now want to do something visible:

import pn
@script("Say Hello!", "Tutorial")
def sayHello():
    d = pn.CurrentDoc()
    Scintilla(d).AppendText(12, "Hello World!")
 

This uses the Scintilla API method AppendText to add the string “Hello World!” to your document (12 is the number of characters in that string). There are a number of functions in the Scintilla API that can be made much easier to use from Python, and that will happen over time.

I’ll post some more documentation over the next few days, hopefully leading up to a release!