public
Description: Run programs in the Emacs buffer holding their source, seeing their output inline, interactively.
Homepage: http://wry.me/project/halp
Clone URL: git://github.com/darius/halp.git
halp / ghcihalp.py
100755 96 lines (84 sloc) 2.726 kb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
#!/usr/bin/env python
"""
Run a Halp-extended .lhs sourcefile from stdin; write to stdout the
same sourcefile with evaluation results placed inline.
"""
 
import os
import re
import subprocess
import sys
import tempfile
 
dbg = False
 
ext = sys.argv[1]
 
input = [line for line in sys.stdin if not line.startswith('-- | ')]
if input and not input[-1].endswith('\n'):
    input[-1] += '\n'
input.append('\n')
if ext == '.hs':
    input.append('aouhtnuoeahn = 0 -- Make sure the file has *some* code.\n')
else:
    input.append('> aouhtnuoeahn = 0 -- Make sure the file has *some* code.\n')
 
module_name = 'Main'
defn_lines = []
eval_line_numbers = []
eval_lines = []
for i, line in enumerate(input):
    if line.startswith('--- '):
        eval_line_numbers.append(i+1)
        eval_lines.append(line[len('--- '):])
    else:
        m = re.search(r'module (.*) where', line) # TODO: more specific
        if m:
            module_name = m.group(1)
        defn_lines.append(line)
 
if dbg:
    print eval_line_numbers
    print ''.join(eval_lines)
 
fd, main_lhs = tempfile.mkstemp(ext)
try:
    os.write(fd, ''.join(defn_lines))
    os.close(fd)
    ghci = subprocess.Popen(['ghci', main_lhs],
                            stdin=subprocess.PIPE,
                            stdout=subprocess.PIPE,
                            stderr=subprocess.STDOUT) # for now
    ghci.stdin.write(''.join(eval_lines))
    results, foo = ghci.communicate()
finally:
    os.unlink(main_lhs)
 
if dbg:
    print results, foo
    print ''
 
def count(it):
    n = 0
    for flag in it:
        if flag:
            n += 1
    return n
 
prompt = '*%s> ' % module_name
result_lines = results.split('\n')
output = input[:-2]
for j, r in enumerate(result_lines):
    m = re.search(r'[.]lhs:(\d+):(\d+):', r)
    if m:
        error_line_num = int(m.group(1))
        output_line_num = (error_line_num
                           + count(lnum < error_line_num
                                   for lnum in eval_line_numbers))
        output.insert(output_line_num, '-- | At column %s:\n' % m.group(2))
        output_line_num += 1
        for plaint_line in result_lines[j+1:]:
            if plaint_line.startswith('Failed, modules loaded:'): break
            output.insert(output_line_num, '-- | %s\n' % plaint_line)
            output_line_num += 1
        break
    if r.startswith(prompt):
        i = 0
        for r in result_lines[j:]:
            if r.startswith(prompt):
                result = r[len(prompt):]
                if result.startswith('Leaving GHCi.'): break
                output.insert(eval_line_numbers[i] + i, '-- | %s\n' % result)
                i += 1
        break
 
sys.stdout.write(''.join(output).replace('\r\n', '\n'))