Skip to content

Commit d19cacf

Browse files
committed
got static sketches working, misc fixes
1 parent d272ae6 commit d19cacf

File tree

6 files changed

+90
-52
lines changed

6 files changed

+90
-52
lines changed

README.md

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,32 +9,33 @@ Inspired by the handsome [processing.py](https://github.com/jdf/processing.py).
99

1010
This is very much a work-in-progress. Don't expect it to work very well right now.
1111

12-
To install: unzip PythonMode.zip into "{your sketchfolder}/modes/PythonMode" and restart Processing.
12+
To install: unzip PythonMode.zip into "{your sketch folder}/modes/PythonMode" and restart Processing.
1313

1414
Check build.xml for building instructions.
1515

1616
Done:
1717
- Basic functionality- running python code
1818
- Basic indentation & highlighting
19+
- Basic preprocessor
1920

2021
Currently working on:
21-
- Preprocessor
22+
- Architechture
2223

2324
Future work:
2425
- Better autoindent & syntax highlighting
26+
- Proper parser for the preprocessor
2527
- REPL for live coding
2628

27-
As I don't have the preprocessor done, code isn't very pretty right now, but it works!
2829
A working sketch (copy and paste into the PDE to try it out!):
2930

30-
class Placeholder(PApplet):
31-
def setup(self):
32-
self.size(200, 200)
33-
self.background(0)
34-
self.noStroke()
35-
self.ellipseMode(PApplet.CENTER)
31+
def setup():
32+
size(300, 300)
33+
smooth()
34+
stroke(255)
35+
background(0)
3636

37-
def draw(self):
38-
self.ellipse(self.mouseX, self.mouseY, 5, 5)
37+
def draw():
38+
line(mouseX+random(-40, 40), mouseY+random(-40, 40), mouseX, mouseY)
3939

40-
applet = Placeholder()
40+
def keyPressed():
41+
background(0)

release/PythonMode.zip

3.9 KB
Binary file not shown.

src/info/sansgills/mode/python/PythonBuild.java

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
* Class to handle the building of python files.
1717
* Given that python runs as an interpreter, all this does is handle preprocessing.
1818
*
19+
* See BUILD.md for notes.
20+
*
1921
*/
2022

2123
public class PythonBuild {
@@ -50,6 +52,7 @@ public void build() throws Exception{
5052
SketchCode[] parts = sketch.getCode(); //fix'd
5153

5254
//concatenate code strings
55+
//TODO do this in some sort of vaguely intelligent way
5356
for(int i = parts.length-1; i >= 0; i--){ //iterate backwards... it seemed like a good idea at the time
5457
program.append("\n");
5558
program.append(parts[i].getProgram());
@@ -78,13 +81,16 @@ public void build() throws Exception{
7881
//Things we don't need to reload every build
7982
//Some regexes
8083
//A hack, but much less work than a full parser, and we don't need to do very much
81-
private static Pattern getSpecial; //replace mousePressed / keyPressed with
84+
private static Pattern getSpecial; //replace mousePressed / keyPressed /frameRate with getmousePressed, etc.
8285
private static Pattern instanceVars; //replace 'mouseX' with __applet__.mouseX, etc.
86+
private static Pattern findSetup, indent; //for static-mode sketches
8387

8488
static{
85-
getSpecial = Pattern.compile("(?<!def\\s{1,1000})(mousePressed|keyPressed|frameRate)(?!\\s{0,1000}\\()");
89+
getSpecial = Pattern.compile("(?<!def\\s{1,1000})(mousePressed|keyPressed|frameRate)(?![0-9a-zA-Z_])(?!\\s{0,1000}\\()");
8690
instanceVars = Pattern.compile("(mouseX|mouseY|pmouseX|pmouseY|mouseButton|"
87-
+"keyCode|key|pixels|width|height|displayWidth|displayHeight|focused|frameCount)");
91+
+"keyCode|key|pixels|width|height|displayWidth|displayHeight|focused|frameCount)(?![0-9a-zA-Z_])");
92+
findSetup = Pattern.compile("^def\\s+setup\\s*\\(\\s*\\)\\s*:", Pattern.MULTILINE);
93+
indent = Pattern.compile("\r?\n");
8894
}
8995

9096

@@ -104,6 +110,20 @@ private String preprocess(StringBuilder program){
104110

105111
temp = regex.replaceAll("__applet__.$1");
106112

113+
regex = findSetup.matcher(temp);
114+
115+
if(!regex.find()){
116+
//no setup function; static mode sketch
117+
//TODO handle bad indentation
118+
program = new StringBuilder(temp);
119+
program.append("\nnoLoop()\n"); //no need to call draw()
120+
program.insert(0, "def setup():\n"); //put the whole function in setup()
121+
122+
regex = indent.matcher(program);
123+
124+
temp = regex.replaceAll("\n\t"); //indent everything a level! (except the first line)
125+
}
126+
107127
return temp;
108128

109129
}catch(Exception e){
@@ -169,7 +189,6 @@ public String getClassPath() {
169189
+ "PythonMode"
170190
+ File.separator
171191
+ "mode";
172-
System.out.println(jythonModeLib);
173192
cp += Base.contentsToClassPath(new File(jythonModeLib));
174193

175194

src/info/sansgills/mode/python/PythonKeyListener.java

Lines changed: 31 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77

88
import java.awt.*;
99
import java.awt.event.*;
10+
import java.util.regex.Matcher;
11+
import java.util.regex.Pattern;
1012

1113
/**
1214
*
@@ -79,17 +81,10 @@ public boolean keyPressed(KeyEvent event){
7981

8082
case 10: //return
8183
case 13: //also return
82-
char[] text = ptextarea.getText().toCharArray(); //text
83-
int cursorLocation = ptextarea.getCaretPosition(); //location of element to be placed; may be out of bounds
84+
String text = ptextarea.getText(); //text
85+
int cursor = ptextarea.getCaretPosition(); //location of element to be placed; may be out of bounds
8486

85-
int tabs = getTabCount(cursorLocation, text);
86-
87-
String insert = "\n";
88-
for(int i=0; i<tabs; i++){
89-
insert += "\t";
90-
}
91-
92-
ptextarea.setSelectedText(insert);
87+
ptextarea.setSelectedText(getIndent(cursor, text));
9388
break;
9489
}
9590

@@ -98,28 +93,36 @@ public boolean keyPressed(KeyEvent event){
9893
return false;
9994
}
10095

101-
//given an index and a block of text, find the number of tabs in the line containing the index
102-
//TODO dirty hack
103-
int getTabCount(int index, char[] text){
104-
int prev = index-1; //the start of the line
96+
private static Pattern findIndent = Pattern.compile("^((?: |\\t)*)");
97+
private static Pattern incIndent = Pattern.compile(":( |\\t)*(#.*)?$"); //TODO fix; breaks on strings (":#"\n) and so on
98+
99+
String getIndent(int cursor, String text){
100+
if(cursor == 1) return "\n";
105101

102+
int lineStart, lineEnd;
103+
int i;
104+
for(i = cursor - 1; i>=0 && text.charAt(i)!='\n'; i--);
105+
lineStart = i+1;
106+
for(i = cursor - 1; i<text.length() && text.charAt(i)!='\n' ; i++);
107+
lineEnd = i;
106108

107-
//walk till we find the beginning of the line (or text)
108-
while(prev >= 0 && text[prev] != '\n'){
109-
prev--;
110-
}
111-
//prev is now at the previous newline
112-
prev++;
109+
if(lineEnd <= lineStart) return "\n";
110+
111+
String line = text.substring(lineStart, lineEnd);
113112

114-
//prev is now at the beginning of the line
115-
//walk forward, counting tabs
116-
int tabCount = 0;
117-
while(prev < text.length && text[prev] == '\t'){
118-
tabCount++;
119-
prev++;
113+
String indent;
114+
Matcher f = findIndent.matcher(line);
115+
116+
if(f.find()){
117+
indent ='\n' + f.group();
118+
119+
if (incIndent.matcher(line).find()){
120+
indent += '\t';
121+
}
122+
}else{
123+
indent = "\n";
120124
}
121125

122-
return tabCount;
126+
return indent;
123127
}
124-
125128
}

src/info/sansgills/mode/python/wrapper/ProcessingJythonWrapper.java

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package info.sansgills.mode.python.wrapper;
22

3+
import java.awt.GraphicsDevice;
34
import java.util.Arrays;
45
import java.util.Scanner;
56

@@ -26,8 +27,6 @@
2627
*/
2728

2829
public class ProcessingJythonWrapper {
29-
30-
3130
//Read in some scripts from the jar (this is the only one-liner to read in a stream, don't you love java)
3231
static final String prepend;
3332
static final String scrub;
@@ -110,4 +109,13 @@ public static void run(String scriptPath, String[] params){
110109
System.exit(1);
111110
}
112111
}
112+
113+
public static void scrub(){
114+
interp.exec(scrub);
115+
}
116+
117+
public static void runSketch(String[] params, PythonPApplet constructedApplet){
118+
GraphicsDevice displayDevice;
119+
120+
}
113121
}

src/info/sansgills/mode/python/wrapper/PythonPApplet.java

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,13 @@
99

1010
/**
1111
*
12-
* Skeleton class to give applets something to inherit from.
13-
* May contain special things later.
12+
* Class for python applets.
13+
* Instead of overriding, they inject functions into it and it runs them.
14+
*
15+
* Also provides information for creation of PApplet globals.
1416
*
1517
*/
1618

17-
// TODO fix keyPressed & other constants, not working right now (if keyPressed:
18-
// is always true and if keyPressed == True: is always false)
19-
// TODO this looks like naming conflict problems? print keyPressed returns a method...
2019
public class PythonPApplet extends PApplet {
2120

2221
//Accessed from prepend.py
@@ -87,7 +86,15 @@ public void inject(String name, PyFunction function){
8786

8887
@Override
8988
public void setup(){
90-
if(sketchFunctions.containsKey("setup")) sketchFunctions.get("setup").__call__();
89+
try{
90+
if(sketchFunctions.containsKey("setup")) sketchFunctions.get("setup").__call__();
91+
}catch(PyException e){
92+
if(e.getCause() instanceof RendererChangeException){
93+
// Processing uses this to signal a change in renderer
94+
// chuck it up the stack
95+
throw (RendererChangeException) e.getCause();
96+
}
97+
}
9198
}
9299
@Override
93100
public void draw(){

0 commit comments

Comments
 (0)