Revision a3b18f1189b9eacda4430affd533b2787fa077f9 authored by David Gowers on 06 July 2011, 09:34:10 UTC, committed by David Gowers on 06 July 2011, 09:34:10 UTC
1 parent 5bdf6b9
Raw File
jbofacki.py
#!/usr/bin/env python
# Accept lojban input, tab-complete words and -raf-si,
# feed jbofihe or camxes.
# Provide quick colorized word lookups,
# approximate gloss/notes/def search,
# lujvo analysis.
#
# Req: Python 2.5, readline. Also a valid makfa-cli database (run 'makfa update' to get one)
# or use the sample database provided.
#
# Works on Linux or Windows (other platforms may work but haven't been tested.).
#
# Bugs/Lacking aspects:
#
# XXX rework coloring to happen after wrapping.
# XXX define a matches-displayer that shows word type (or class, in case of cmavo)
# XXX parentheses handling is incomplete in some circumstances
# XXX some python functions like sum, dict, etc show up in the completion list
# XXX colorize jbofihe (and camxes?) output
# XXX completion could be context sensitive (some way to prioritize terminators when a
#     scope is open?)
# XXX glosses should be completeable when the input string contains '/'
# XXX wildcards in search (shell style)
# XXX quoting in search (extract quoted sections first. disallow searching for '"' lerfu
# XXX independence from makfa (build our own DB)
# XXX conform to FDO standard for config location
# XXX configure via cmdline.
# XXX sort lujvo < gismu < cmavo
# XXX ignore everything after '#' to allow inline comments (still write the full input to log)
# XXX autopagically use matter for >N(N=20) results
# XXX ... except when redirections '>' are in a query.
# XXX test lujvo analysis more fully.
# XXX possibly SELMAHO? should produce also an item pointing at BPFK pages.
# XXX configurable DB location
#
#    la donri
#        ce'e
#    la samselpla pagbu .e le ve ciksi
#
#        pe'e je
#
#    la .tueis. ce la .tomoj. ce la aidalgol
#        ce'e
#    le darsi gasnu
#
#        pe'e je
#
#    la .djancak.
#        ce'e
#    le nu cipra ci'e la canko kei ku
#
# ckire fa mi
#
# ^ (one bridi, nicely formatted, with afterthought termsets.)


import os
import sys
import re

##### se cuxna
#
#
class Config(object):
    def __init__ (self, rolterciha = '',
                  notcyterciha = '',
                  camxes = ['java','-jar',os.path.expanduser ('~/lojban/lojban_peg_parser.jar')],
                  jbofihe = ['jbofihe','-x','-se'],
                  fadyselcuha = ['jbofihe','-x','-se'],
                  jarco_tuha_le_sidju = True,
                  na_skari = False,
                  vinriha = 'less',
                  mipri_liste = []):
        self.rolterciha = rolterciha
        self.notcyterciha = notcyterciha
        self.camxes = camxes
        self.jbofihe = jbofihe
        self.fadyselcuha = fadyselcuha
        self.jarco_tuha_le_sidju = jarco_tuha_le_sidju
        self.na_skari = na_skari
        self.vinriha = 'less'
rolterciha = ''
notcyterciha = ''
camxes = ['java','-jar',os.path.expanduser ('~/lojban/lojban_peg_parser.jar')]
jbofihe = ['jbofihe','-x','-se']
fadyselcuha = jbofihe
jarco_tuha_le_sidju = True
na_skari = False
vinriha = 'less'
mipri_liste = []

#####
#
#

WINDOWS = False
import platform
if 'indows' in platform.system():
    WINDOWS = True


def tcidu_le_selcuha_vreji ():
    global rolterciha
    global notcyterciha
    global camxes
    global jbofihe
    global fadyselcuha
    global vinriha
    global jarco_tuha_le_sidju
    global na_skari
    global mipri_liste
    try:
        import ConfigParser as configparser
        from ConfigParser import DEFAULTSECT as NOHO
    except ImportError:
        import configparser
        from configparser import DEFAULTSECT as NOHO
    ro_kraselcuha = {
      'logfile' : "~/jbofacki-log.rst",
      'notefile' : "~/jbofacki-notci.rst",
      'disable color' : 'no',
      'camxes path' : './lojban_peg_parser.jar',
      'camxes options' : '',
      'jbofihe path' : './jbofihe',
      'jbofihe options' : '-x -se',
      'default parser' : 'jbofihe',
      'show help at startup' : 'yes',
      'word type blacklist' : '',
      'pager' : 'less',
    }
    path = '.'
    if not WINDOWS:
        from xdg.BaseDirectory import save_config_path
        ro_kraselcuha ['jbofihe path'] = 'jbofihe' # zmiku facki du'o la'e zoi .env. PATH .env.
        # pau xu galfi zoi .tercu'a. pager .tercu'a.
        path = save_config_path ('jbofacki')
    tc = configparser.ConfigParser (ro_kraselcuha)
    le_mohu_tcidu = tc.read ([os.path.join ('.','jbofacki.cfg'),
                              os.path.join (path, 'jbofacki.cfg')])
    if len (le_mohu_tcidu) == 0:
        # co'a paroi vreji le selcuha
        vv = open (os.path.join (path, 'jbofacki.cfg'),'wb')
        tc.write(vv)
        vv.close()
    del le_mohu_tcidu
    rolterciha =  os.path.expanduser (tc.get (NOHO, 'logfile'))
    notcyterciha = os.path.expanduser (tc.get (NOHO, 'notefile'))
    na_skari = tc.getboolean ( NOHO, 'disable color')
    camxes = ['java', '-jar', os.path.expanduser (tc.get (NOHO, 'camxes path'))]
    if len (tc.get (NOHO, 'camxes options')) > 0:
        camxes.extend (tc.get (NOHO, 'camxes options').split (' '))
    jbofihe = [os.path.expanduser (tc.get (NOHO, 'jbofihe path'))]
    if len (tc.get (NOHO, 'jbofihe options')) > 0:
        jbofihe.extend (tc.get (NOHO, 'jbofihe options').split (' '))
    fadyselcuha = tc.get (NOHO, 'default parser')
    if fadyselcuha == 'jbofihe':
        fadyselcuha = jbofihe
    elif fadyselcuha == 'camxes':
        fadyselcuha = camxes
    else:
        raise ValueError ('%r as a choice of default parser is invalid' % fadyselcuha)
    jarco_tuha_le_sidju = tc.getboolean (NOHO, 'show help at startup')
    mipri_liste = tc.get (NOHO, 'word type blacklist')
    mipri_liste = mipri_liste.split(';')
    mipri_liste = [p for p in mipri_liste if p in ('cmene',
                                                   "fu'ivla",
                                                   'cmavo',
                                                   'experimental',
                                                   'experimental cmavo',
                                                   'experimental gismu',
                                                   'gismu',
                                                   'lujvo')]
    vinriha = [tc.get (NOHO, 'pager')]
    try:
        vv = open (os.path.join (path, 'jbofacki.cfg'),'wb')
        tc.write(vv)
        vv.close()
    except AttributeError: # la pieton.cib. djica tu'a zoi .tadji. w .tadji.
        vv = open (os.path.join (path, 'jbofacki.cfg'),'w')
        tc.write(vv)
        vv.close()


tcidu_le_selcuha_vreji ()

#####

# le krasi du zoi .python.
#
# > from pygments.console import codes
# > print codes
#
# .python.

codes = {'': '',
'yellow': '\x1b[33;01m',
'blink': '\x1b[05m',
'lightgray': '\x1b[37m',
'underline': '\x1b[04m',
'darkyellow': '\x1b[33m',
'blue': '\x1b[34;01m',
'darkblue': '\x1b[34m',
'faint': '\x1b[02m',
'fuchsia': '\x1b[35;01m',
'black': '\x1b[30m',
'white': '\x1b[01m',
'red': '\x1b[31;01m',
'brown': '\x1b[33m',
'turquoise': '\x1b[36;01m',
'bold': '\x1b[01m',
'darkred': '\x1b[31m',
'darkgreen': '\x1b[32m',
'reset': '\x1b[39;49;00m',
'standout': '\x1b[03m',
'darkteal': '\x1b[36;01m',
'darkgray': '\x1b[30;01m',
'overline': '\x1b[06m',
'purple': '\x1b[35m',
'green': '\x1b[32;01m',
'teal': '\x1b[36m',
'fuscia': '\x1b[35;01m'}

if WINDOWS or 1:
    # cancel color codes on win; API calls are needed :|
    for k,v in dict(codes).items():
        codes[k] = ''

tersuhi_skari = codes['purple']
valsi_skari = codes['white']
klesi_skari = codes['darkgreen']
rafsi_skari = codes['teal']
tcita_skari = codes['brown']
cmavo_skari = codes['blue']
gismu_skari = codes['darkgreen']
lujvo_skari = codes['green']
jorne_skari = codes['darkgreen']
troci_skari = codes['red']
selmaho_skari = codes['darkred']
fuhivla_skari = codes['fuchsia']
pinka_skari = codes['darkgray']
xruti = codes['reset']

# cpacu le jorne la makfa
manri_jorne = {'A': ((14, 6),),
            'BAI': ((9, 6),),
            'BAhE': ((19, 11),),
            'BE': ((5, 7),),
            'BEI': ((5, 7),),
            'BEhO': ((5, 7),),
            'BIhE': ((18, 5),),
            'BIhI': ((14, 16),),
            'BO': ((5, 3), (15, 6), (18, 17),),
            'BOI': ((18, 6),),
            'BU': ((17, 4),),
            'BY': ((17, 2),),
            'CAI': ((13, 4),),
            'CAhA': ((10, 19),),
            'CEI': ((7, 5),),
            'CEhE': ((14, 11), (16, 7),),
            'CO': ((5, 8),),
            'COI': ((6, 11), (13, 14),),
            'CU': ((9, 2),),
            'CUhE': ((10, 24),),
            'DAhO': ((7, 13),),
            'DOI': ((13, 14),),
            'DOhU': ((13, 14),),
            'FA': ((9, 3),),
            'FAhA': ((10, 2),),
            'FAhO': ((19, 15),),
            'FEhE': ((10, 11),),
            'FEhU': ((9, 5),),
            'FIhO': ((9, 5),),
            'FOI': ((17, 6),),
            'FUhA': ((18, 16),),
            'FUhE': ((19, 8),),
            'FUhO': ((19, 8),),
            'GA': ((14, 5),),
            'GAhO': ((14, 16),),
            'GEhU': ((8, 3),),
            'GI': ((14, 5),),
            'GIhA': ((14, 3),),
            'GOI': ((8, 3),),
            'GOhA': ((7, 6),),
            'GUhA': ((14, 3),),
            'I': ((19, 2),),
            'JA': ((14, 3),),
            'JAI': ((9, 12),),
            'JOI': ((14, 14),),
            'JOhI': ((18, 15),),
            'KE': ((5, 5),),
            'KEI': ((11, 1),),
            'KEhE': ((5, 5),),
            'KI': ((10, 13),),
            'KOhA': ((7, 1),),
            'KU': ((6, 2), (10, 1),),
            'KUhE': ((18, 6),),
            'KUhO': ((8, 1),),
            'LA': ((6, 2),),
            'LAU': ((17, 14),),
            'LAhE': ((6, 10),),
            'LE': ((6, 2),),
            'LEhU': ((19, 9),),
            'LI': ((18, 5),),
            'LIhU': ((19, 9),),
            'LOhO': ((18, 17),),
            'LOhU': ((19, 9),),
            'LU': ((19, 9),),
            'LUhU': ((6, 10),),
            'MAI': ((18, 19), (19, 1),),
            'MAhO': ((18, 6),),
            'ME': ((5, 10), (18, 1),),
            'MEhU': ((5, 11),),
            'MOI': ((5, 11),),
            'MOhE': ((18, 18),),
            'MOhI': ((10, 8),),
            'NA': ((14, 3), (15, 7),),
            'NAI': ((14, 3), (15, 7),),
            'NAhE': ((15, 4),),
            'NAhU': ((18, 18),),
            'NIhE': ((18, 18),),
            'NIhO': ((19, 3),),
            'NOI': ((8, 1),),
            'NU': ((11, 1),),
            'NUhA': ((18, 19),),
            'NUhI': ((14, 11), (16, 7),),
            'NUhU': ((14, 11),),
            'PA': ((18, 2),),
            'PEhE': ((14, 11),),
            'PEhO': ((18, 6),),
            'PU': ((10, 4),),
            'RAhO': ((7, 6),),
            'ROI': ((10, 9),),
            'SA': ((19, 13),),
            'SE': ((5, 1), (9, 4),),
            'SEI': ((19, 12),),
            'SEhU': ((19, 12),),
            'SI': ((19, 13),),
            'SOI': ((7, 8),),
            'SU': ((19, 13),),
            'TAhE': ((10, 9),),
            'TEI': ((17, 6),),
            'TEhU': ((18, 15),),
            'TO': ((19, 12),),
            'TOI': ((19, 12),),
            'TUhE': ((19, 2),),
            'TUhU': ((19, 2),),
            'UI': ((13, 1),),
            'VA': ((10, 2),),
            'VAU': ((14, 9),),
            'VEI': ((18, 5),),
            'VEhA': ((10, 5),),
            'VEhO': ((19, 5),),
            'VIhA': ((10, 7),),
            'VUhO': ((8, 8),),
            'VUhU': ((18, 5),),
            'XI': ((18, 13),),
            'Y': ((19, 14),),
            'ZAhO': ((10, 10),),
            'ZEI': ((4, 6),),
            'ZEhA': ((10, 5),),
            'ZI': ((10, 4),),
            'ZIhE': ((8, 4),),
            'ZO': ((19, 10),),
            'ZOI': ((19, 10),),
            'ZOhU': ((16, 2), (19, 4),)}

# .ije cpacu le kuspe mulno datni la makfa

mulno_selmaho = {'BE': 'BEhO',
                 'PA': 'BOI',
                 'BY': 'BOI',
                 'COI': 'DOhU',
                 'DOI': 'DOhU',
                 'FIhO': 'FEhU',
                 'GOI': 'GEhU',
                 'NU': 'KEI',
                 'KE': 'KEhE',
                 'LE': 'KU',
                 'LA': 'KU',
                 'PEhO': 'KUhE',
                 'NOI': 'KUhO',
                 'LU': 'LIhU',
                 'LI': 'LOhO',
                 'LAhE': 'LUhU',
                 'NAhE+BO': 'LUhU',
                 'ME': 'MEhU',
                 'NUhI': 'NUhU',
                 'SEI': 'SEhU',
                 'SOI': 'SEhU',
                 'TO': 'TOI',
                 'TUhE': 'TUhU',
                 'TEI': 'FOI',
                 'VEI': 'VEhO'}

def facki_fi_lo_valsi (valsi):
    return [v in ro_valsi for v in valsi]

def galfi_le_porsi (valsi, se_porsi = 'cmene'):
    valsi = list (valsi)
    if se_porsi == 'cmene':
        valsi.sort()
    elif se_porsi == 'rafsi':
        valsi.sort(key = lambda v:"".join(valsi_datni['rafsi']))
    else:
        valsi.sort(key = lambda v:valsi_datni[se_porsi])
    return valsi

tersuhi_rex = re.compile ('([a-z][0-9])')
pinka_rex = re.compile ('([([][^\])]+[)\]])')
valsi_rex = re.compile ('(\{[a-z \']+\})')
se_ciska_rex = re.compile ('("[^"]+")')
selmaho_rex = re.compile ('([A-Zh]+)(\\.+)?([A-Zh]+)?') #cumki srera sera'a eg LU.. LI'U
selmaho_cfari_rex = re.compile ('([A-Zh]+)')
selmaho_pagbu_rex = re.compile ('([A-Zh]+)(\*)?([0-9a-z]+)?')
jorne_rex = re.compile('(http://dag.github.com/cll/[0-9/]+)')


def skagau (se_ciska, rex, skari):
    if not se_ciska:
        return ''
    return rex.sub (skari + '\\1' + xruti, se_ciska)

def klesi_skagau (klesi):
    klesi = klesi.replace ("experimental", troci_skari + "experimental" + xruti)
    klesi = klesi.replace ("lujvo", lujvo_skari + 'lujvo' + xruti)
    klesi = klesi.replace ("gismu", gismu_skari + 'gismu' + xruti)
    klesi = klesi.replace ("cmavo", cmavo_skari + 'cmavo' + xruti)
    klesi = klesi.replace ("fu'ivla", fuhivla_skari + "fu'ivla" + xruti)
    return klesi

def selmaho_skagau (selmaho):
    if not selmaho:
        return ''
    if '...' in selmaho:
        return "%s%s%s...%s%s%s" % (selmaho_skari, selmaho[:selmaho.find('.')], xruti,
                                    selmaho_skari, selmaho[selmaho.rfind('.')+1:], xruti)
        #return selmaho_rex.sub (selmaho_skari + '\\1' + xruti + '\\2' + selmaho_skari + '\\3' + xruti, selmaho)
    return selmaho_skari + selmaho + xruti

def rafsi_skagau (rafsi):
    if len(rafsi) == 0:
        return ''
    return rafsi_skari + "\t" + "\t".join(rafsi) + xruti

def tersuhi_skagau (tersuhi):
    te_pruce = []
    zasni = []
    for ts, ts_tcita in tersuhi.items():
        #print ts, ';',ts_tcita
        for da, de in ts_tcita:
            if da and (not de):
                zasni.append (' %s%r%s' % ( tcita_skari, da,
                                            xruti))
            else:
                zasni.append ('%s%r%s in sense %s%r%s' % (tcita_skari,
                                                da, xruti,
                                                tcita_skari,
                                                de, xruti))
        te_pruce.append (("%sx%d%s " % (tersuhi_skari,
                                         ts,xruti) +
                                         ", ".join(zasni)))
    return "; ".join(te_pruce)


def sidju (n):
    s = """\t\t%Wla jbofacki%/
    \t\t===========

    Note: word lookup requires a makfa db. Installing makfa-cli and
          running 'makfa update' should make one.
    Also, you can configure various behaviour via editing
    ~/.jbofacki.cfg (non-Windows OS) or .jbofacki.cfg (on Windows)
    ------
    Enter text to parse with default parser [usually jbofihe].

    \tplace
    \t\t"%G!%/" before the text to %Wparse with alternate parser%/
    \t\t"%G?%/"\t%Wdefine text%/,
    \t\t"%G/%/"\t%Wfind%/ text in definitions,
    \t\t"%G%%/"\t%Wsplit a lujvo%/,
    \t\t"%G:%/"\t%Wwrite a note%/,
    \t\t"%G:?%/"\t%Wshow last 10 notes%/,
    \t\t"%G??%/" for this help, or
    \t\t"%G?%/" for less verbose help.


    \t\t"%G?%/%B-raf-%/" = show definition of the gismu with rafsi "raf"
    \t\t"%G?%/%BCAhA%/" = show definition for all cmavo of CAhA selma'o

    Tab-completion of lojban words, -raf-si, selmaho is available at all times,
    as are the usual Readline niceties.
                    *** Type Ctrl+D to exit. ***
    ....
    .i ai cfari"""

    s2 = """Enter bridi to parse, or..\n

    "%W!%/" = parse via alternate parser,
    "%W/%/" = find,
    "%W:%/" = make note, \t"%W:?%/" = show last 10 notes,
    "%W%%/" = split lujvo, \t"%W/%/" search definitions for keywords,
    "%W?%/" =  define words (expanding rafsi %G-raf-%/ and selmaho %GCAhA%/)
    "%W?%/"(alone) = this help\t"%W??%/" = verbose help.

    Tab completion is available at all times."""

    if n > 0:
        s2 = s

    s2 = s2.replace ('%W', codes['white'])
    s2 = s2.replace ('%G', codes['green'])
    s2 = s2.replace ('%B', codes['blue'])
    s2 = s2.replace ('%/', xruti)
    print (s2)

def tersuhi_sisku (datni, valsi):
    tersuhi = datni['places']
    for tersuhi, tcita in tersuhi.items():
        for a, b in tcita:
            if valsi in a:
                return True
            if not b:
                continue
            if valsi in b:
                return True
    return False

def xu_na_jarco (valsi):
    t = valsi_datni[valsi]['type']
    for m in mipri_liste:
        if m in t:
            return True
    return False

def ro_selkai_sisku (pagbu):
    mipri = set ()
    ni_mipri = 0
    te_pruce = []
    for cmene, datni in valsi_datni.items():
        mapti_kau = True
        for p in pagbu:
            tohe = False
            if p.startswith ('-'):
                tohe = True
                p = p[1:]
            jehu = not (p in cmene or (datni['notes'] and p in datni['notes']) \
                   or p in datni['definition'] or tersuhi_sisku (datni, p)
                   or (datni['selmaho'] and p in datni['selmaho']) or
                   p in datni['type']
                   )
            if tohe:
                jehu = not jehu
            if jehu:
                mapti_kau = False
            if xu_na_jarco (cmene):
                # le vi valsi ku nenri le mipri liste
                mipri.add (datni['type'])
                ni_mipri += 1
                mapti_kau = False;
                break;

        if mapti_kau == True:
            te_pruce.append (cmene)
    return te_pruce, ni_mipri, mipri

def jarco (valsi, se_porsi = 'cmene'):
    te_pruce = []
    # remove
    ro_rapli = [v for v in valsi if valsi.count(v) > 1]
    for r in ro_rapli:
        while valsi.count(r) > 1:
            valsi.remove (r)
    valsi = galfi_le_porsi (valsi, se_porsi)
    # banro le selma'o ja rafsi
    valsi2 = []
    for v in valsi:
        if selmaho_rex.match(v):
            selmaho_zasni = []
            if '..' in v:
                purci = v[:v.find('.')]
                balvi = v[v.rfind('.')+1:]
            else:
                purci = v
                balvi = None
            for v2 in (purci, balvi):
                if not v2:
                    continue
                for cmene, datni in valsi_datni.items():
                    if not datni['selmaho']:
                        continue
                    selmaho = datni['selmaho']

                    if selmaho:
                        selmaho = selmaho.replace('*','')
                        if v2 == selmaho or selmaho.startswith (v2):
                            # UI -> UI[12345678][abc]?
                            # UI3 facki [UI3a, UI3b, ...]
                            selmaho_zasni.append (cmene)
            selmaho_zasni.sort (key = \
                                lambda v: valsi_datni[v]['selmaho'].replace('*', '') +\
                                          v)
            valsi2.extend (selmaho_zasni)
        elif len(v) in (5,6) and v.startswith ('-') and v.endswith ('-'):
            rafsi = v[1:-1]
            for cmene, datni in valsi_datni.items():
                    if rafsi in datni['rafsi']:
                        valsi2.append (cmene)
                        break; # no more than one valsi should be assigned the same rafsi
        else:
            valsi2.append (v)
    for v in valsi2:
        try:
            datni = valsi_datni[v]
        except KeyError:
            te_pruce.append ((v, selmaho_skari + 'na facki' + xruti))
            continue
        se_valsi = datni['definition']
        se_valsi = skagau (se_valsi, pinka_rex, pinka_skari)
        se_valsi = skagau (se_valsi, tersuhi_rex, tersuhi_skari)
        # skagau [a-z][0-9]
        # skagau (qualifiers)
        notci = datni['notes']
        notci = skagau (notci, pinka_rex, pinka_skari)
        notci = skagau (notci, valsi_rex, jorne_skari)
        notci = skagau (notci, tersuhi_rex, tersuhi_skari)
        rafsi = rafsi_skagau (datni['rafsi'])
        tersuhi = tersuhi_skagau (datni ['places'])
        # skagau {valsi}
        jorne = ''
        selmaho = datni['selmaho']
        if selmaho:
            cfari = selmaho_cfari_rex.match (selmaho).expand('\\1')
            if cfari in manri_jorne:
                jorne = ", ".join(['<http://dag.github.com/cll/%d/%d/>' % (a,b) for a,b in manri_jorne[cfari]])
                jorne = skagau (jorne, jorne_rex, jorne_skari)
        if selmaho in mulno_selmaho:
            selmaho += '...' + mulno_selmaho[selmaho]
        selmaho = selmaho_skagau (selmaho)
        klesi = klesi_skagau (datni['type'])
        zasni = " ".join ([klesi,selmaho,rafsi])
        te_pruce.append ( (v, zasni, se_valsi, tersuhi, notci, jorne))
    return te_pruce

def selmaho (valsi_ja_selmaho):
    if type(valsi_ja_selmaho) == list or valsi_ja_selmaho in ro_valsi:
        valsi = valsi_ja_selmaho
        if type(valsi) != list:
            valsi = [valsi]
        valsi = facki_fi_lo_valsi (valsi)
        # XXX look up all the valsi, return their selmaho
    else:
        raise NotImplementedError ('selmaho klesi zgana')
        # XXX look up all the selmaho in the specified class

from textwrap import TextWrapper
selciha_polje = TextWrapper(80)
selciha_polje.subsequent_indent = '\t'
def jarco_xire (tcita, tebai = sys.stdout):
    def jc (s):
        tebai.write (s.encode ('utf-8'))
        tebai.write ('\n')
    j = tcita
    for da in j:
        zasni = []
        jc ('\n' + codes['white'] + da[0] + xruti
            + "\t" + da[1])
        if len (da) < 4:
            continue;
        for l in selciha_polje.wrap ("\t" + da[2]):
            jc (l)
        for l in selciha_polje.wrap ("\t   " + da[3]):
            jc (l)
        for i, de in enumerate (da[4:]):
            if len(de) > 1:
                zasni.append("\t   " + de)
        for l in selciha_polje.wrap ("\n".join(zasni)):
            jc (l)
    #selciha.append ('\n')
    #print selciha_polje.wrap ()
    jc ('')

valsi_datni = None
ro_valsi = None
mulno_selcmi = {}

def tcidu_sumti ():
    """ tcidu le minde sumti
    
    cumki sumti:
    
     -e minde
     -s selpla_minde_cmene
     
    """
    from optparse import OptionParser
    p = OptionParser ()
    p.add_option ('-e','--minde', dest= "terminde",
                  help = "pa terminde zi rinka .i ka'e sepli fi \";\"",
                  action = 'append',
                  default = [])
    p.add_option ('-s','--selpla-minde', dest= "selpla",
                  help = "liste lo terminde",
                  action = 'append',
                  default = [])
    suhi, args = p.parse_args ()
    terminde = []
    for v in suhi.terminde:
        v = v.split (';')
        v = [v2.split('\n') for v2 in v]
        v2 = []
        for v3 in v:
            v2.extend(v3)
        terminde.extend (v2)
    for v in suhi.selpla:
        f = open (v,'rb')
        v = f.read()
        f.close()
        v = v.split (';')
        v = [v2.split('\n') for v2 in v]
        v2 = []
        for v3 in v:
            v2.extend(v3)
        terminde.extend (v2)
    return terminde


def tcidu_datni ():
    global valsi_datni
    global ro_valsi
    from cPickle import load
    if os.path.exists (os.path.expanduser('~/.makfa.dump')):
        f = open (os.path.expanduser('~/.makfa.dump'), 'rb')
        valsi_datni = load(f)
    else:
        if os.path.exists ('./.makfa.dump'):
            f = open ('./.makfa.dump', 'rb')
            valsi_datni = load(f)
        else:
            print ('no makfa dump found. search and word lookup disabled.')
            valsi_datni = {'entries':{},'order':[]}
    ro_valsi = valsi_datni['order']
    valsi_datni = valsi_datni['entries']
    for valsi in ro_valsi:
        if valsi_datni[valsi]['type'] not in mipri_liste:
            mulno_selcmi[valsi] = True

    for valsi, datni in valsi_datni.items():
        if datni['rafsi'] != None and len(datni['rafsi']) > 0:
            for r in datni['rafsi']:
                mulno_selcmi["-%s" % r] = True
        if datni['selmaho'] and datni['selmaho'] not in mulno_selcmi:
            mulno_selcmi[datni['selmaho']] = True

#cpacu fi la makfa

def linji_clani():
    if 'COLUMNS' in os.environ:
        return int(os.environ.get('LINES', 25)), int(os.environ['COLUMNS'])
    def ioctl_GWINSZ(fd):
        try:
            import fcntl, termios, struct
            return struct.unpack('hh',
                                 fcntl.ioctl(fd, termios.TIOCGWINSZ, '1234'))
        except:
            return None
    cr = ioctl_GWINSZ(0) or ioctl_GWINSZ(1) or ioctl_GWINSZ(2)
    if not cr:
        try:
            cr = ioctl_GWINSZ(os.open(os.ctermid(), os.O_RDONLY))
        except:
            pass
    if not cr or cr[1] < 1:
        cr = os.environ.get('LINES', 25), os.environ.get('COLUMNS', 80)
    return int(cr[0]), int(cr[1])


PYTHON_MINDE         = 0x1
JMINA_LE_NOTCI       = 0x2
DRATA_JUFYJMI        = 0x4
JARCO_LE_KA_SE_VALSI = 0x8
CISKA                = 0x10
TCIDU                = 0x20


def sepuhe_jimpe (sepuhe):
    # notice :?!
    # notice >< redirect (<=1ro) -- this is always "send the results of query X(lvalue) to file Y(rvalue)"
    # strip # from the sentence-to-parse while logging the full input.
    # return what to log, what to parse, flags,  and extra data (redirect target, currently)
    #
    sepuhe = sepuhe.strip()
    if sepuhe.strip() == '$':
        return '$ -> entered python console', None, PYTHON_MINDE, None
    # zoi .ly. ? .ly. na nitcu fi le nu zoi .ry. > .ry. lerfu
    # zgana le se pruce ja te pruce galfi
    # <> (< purci)
    # zgana le drata jufyjmi tcita
    # "!"
    # zgana le valsi ciksi tcita
    # "?"

purci = None

mulno_selcmi = {}


def mapti_gismu (lujvo, vi):
    # XXX masno
    pagbu = lujvo[vi:vi+5]
    if (len(pagbu) < 5):
        return False
    satci = False
    pagbu = lujvo[vi:vi+5]
    if vi == (len(lujvo) -5) and len (lujvo) > 5:
        satci = True
    else:
        if lujvo[vi+4] not in 'yr':
            return False # not a valid gismu-in-lujvo form
        pagbu = pagbu[:-1]

    for valsi in ro_valsi:
        if len(valsi) == 5 and valsi_datni[valsi]['type'] == 'gismu':
            if satci:
                if valsi == pagbu:
                    return valsi
            else:
                if valsi[:4] == pagbu:
                    return valsi
    return False

def lujvo_katna (lujvo):
    #
    # cases like this {terdi'ajbari}
    # strictly require distinction between GISMU before word end and GISMU
    # at word end. The latter can preserve it's final V, the former must have a J
    C = 'bcdfgjklmnprstvxyz'
    V = 'aeiou'
    H = "'"
    J = 'yrm' # m is usually not valid.

    # CVV CV'V CVC CCV
    #
    # gismu : CCVCV | CVCCV
    i = 0

    if lujvo[-1] in C or lujvo[-1] == 'y':
        raise ValueError ('toldra vlatai')

    tepuhe = []

    while i < len(lujvo):
        #print "cfari lerfu %r" % lujvo[i]
        if lujvo[i] not in C:
            raise ValueError ('cizra lujvo? [djica C]')
        i+=1
        if lujvo[i] in C:
            i+=1
            if lujvo[i] in V:
                if i < len(lujvo) - 1 and lujvo[i+1] in C and lujvo[i+2] in (V+J): # CCVCV gismu
                   if mapti_gismu (lujvo, i-2):
                       i+= 3
                       zasni = lujvo[i-5:i]
                       if zasni[-1] not in V:
                           tepuhe.append (zasni[:-1])
                           tepuhe.append (zasni[-1])
                       else:
                           tepuhe.append (zasni)
                       continue
                i+=1
                tepuhe.append (lujvo[i-3:i])
                continue # XXX any hyphenation needed here? yes,
            raise ValueError ('cizra lujvo? [djica V]')
        elif lujvo[i] in V:
            i+=1
            if lujvo[i] in V: # what follows can't be a gismu end
                i+=1
                tepuhe.append (lujvo[i-3:i])
                # hyphenation may be needed
                if i < len(lujvo) and lujvo[i] in 'mr': #y can't follow a V
                    tepuhe.append (lujvo[i])
                    i+=1
                continue
            elif lujvo[i] == H: # what follows can't possibly be the end of a gismu.
                i+=1
                if lujvo[i] in V:
                    i+=1
                    tepuhe.append (lujvo[i-4:i])
                    if i < len(lujvo) - 1 and lujvo[i] in 'mr' and lujvo[i+1] in C: #y can't follow a V
                        tepuhe.append (lujvo[i])
                        i+=1
                    continue
                    # hyphenation? yes, see Newton Unit (SI) lujvo
            elif lujvo[i] in C:
                if i < len(lujvo) - 1 and lujvo[i+1] in C and lujvo[i+2] in (V+J): #CVCCV
                   if mapti_gismu (lujvo, i-2):
                       i+= 3
                       zasni = lujvo[i-5:i]
                       if zasni[-1] not in V:
                           tepuhe.append (zasni[:-1])
                           tepuhe.append (zasni[-1])
                       else:
                           tepuhe.append (zasni)
                       continue
                i+=1
                tepuhe.append (lujvo[i-3:i])
                if i < len(lujvo) - 1  and lujvo[i] in J and lujvo[i+1] in C:
                    tepuhe.append (lujvo[i])
                    i+=1
                #XXX detect invalid initial pair + hyphen
                continue
            raise ValueError ('cizra lujvo? [djica VH]')
    return tepuhe




def jei_kau_snura ():
    return True

def zbasu_liste (valsi):
    # banro la'e zo CMAVO
    # je -raf-si xu
    #
    # manri nu se porsi kei pruce
    # canonical word-type sort?
    pass

def python (log):
    # python console.
    # for doing advanced lookups.
    raise NotImplementedError ('python minde')

def vreji_pa_notci (notci):
    notci_vv = open (notcyterciha, 'ab')
    notci_vv.write (notci)
    notci_vv.write ('\n')
    notci_vv.close ()
    print ("wrote note %s..' to %s" % (repr(notci[:7])[:-1], notcyterciha))

def cunso_veldetri ():
    # zbasu lo ve detri sera'a lo nanca be li re
    import random
    cmavo = [c for c in ro_valsi if 'cmavo' in valsi_datni[c]['type'] and 'cluster' not in valsi_datni[c]['type']]
    gismu = [c for c in ro_valsi if 'gismu' in valsi_datni[c]['type']]
    random.shuffle (cmavo)
    random.shuffle (gismu)
    def fatri (liste):
        seljmi = len (liste) / float(365*2)
        terkac = 0.
        puterkac = 0
        while len(liste) > 0:
            terkac += seljmi
            selsuj = int (terkac - puterkac)
            if selsuj > 0:
               yield [liste.pop() for v in range(selsuj)]
               puterkac = int(terkac)
            else:
               yield []
    veldet = [list() for v in range (365*2)]
    for i,c in enumerate (fatri (gismu)):
        veldet[i].extend (c)
    for i,c in enumerate (fatri (cmavo)):
        veldet[i].extend (c)
    return veldet

def jarco_le_ka_vlalihi_pe_le_notci (clani):
    try:
        notci_tt = open (notcyterciha, 'rb')
    except IOError:
        return
    vlalihi = notci_tt.readlines()
    notci_tt.close()
    for vl in vlalihi [-clani:]:
        print (vl)
    del vlalihi

def vreji_pa_pruce_datni (datni):
    rtc_vv = open (rolterciha, 'ab')
    rtc_vv.write (datni)
    rtc_vv.write ('\n')
    rtc_vv.close ()

def main ():
    global purci
    try:
        # catlu zoi .url. http://bugs.python.org/issue5256 .url.
        # .i bakfu le selgalfi
        #             be la piton noi farvi li 2 pi 7 pi 2
        # .i gafygau  ki'u
        #             le du'u ma'a na djica 
        #                             lo nu ma'a mulgau 
        #                                        lo nu cmene fi la piton
        # .i pau nelci le mi viska platu .u'i xu
        from patched_rlcompleter import Completer
        import readline
    except:
        print ('Readline not found, history/completion etc will not be available.')
    tcidu_datni()
    if not jei_kau_snura ():
        print ('something undefined happened. :/')
        sys.exit()
    drata_lerfu = "?/:%"
    try:
        m = Completer (mulno_selcmi)
        readline.parse_and_bind ('tab: complete')
        readline.set_completer (m.complete)
        readline.set_completer_delims (drata_lerfu + ". ")
    except:
        pass
    if jarco_tuha_le_sidju:
        sidju (0)
    denpa_notci = rafsi_skari + 'mo ' + cmavo_skari + ': ' + xruti
    terminde = tcidu_sumti ()
    while 1:
        try:
            if len(terminde) > 0:
                sepuhe = terminde.pop(0)
                print ('--->\t"%s"' % sepuhe)
            else:
                sepuhe = raw_input(denpa_notci)
            sepuhe = sepuhe.strip()
            if sepuhe == '':
                continue
        except EOFError:
            sys.stdout.write('\n')
            sys.exit()
        command = fadyselcuha
        f = None
        if sepuhe.startswith ('!'):
            if fadyselcuha == jbofihe:
                command = camxes
            else:
                command = jbofihe
            from subprocess import Popen, PIPE
            try:
                f = Popen (command, stdin = PIPE, stdout = PIPE)
            except OSError:
                print ('Your alternate parser (%r) doesn\'t appear to be present!' % command)
                print ('Please fix your setting in ~/.jbofacki.cfg to point at a valid executable.')
                continue
            if len (sepuhe) > 1:
                f.stdin.write (sepuhe[1:])
                purci = sepuhe[1:]
            else:
                if purci != None:
                    f.stdin.write(purci)
        elif sepuhe[0] in drata_lerfu or sepuhe[-1] in drata_lerfu:
            # ? (look up a word)
            #
            if sepuhe[0] in drata_lerfu:
                char = sepuhe[0]
                sepuhe = sepuhe[1:]
            else:
                char = sepuhe[-1]
                sepuhe = sepuhe[:-1]
            if char == '?':
                if len (sepuhe) == sepuhe.count ('?'):
                    sidju(sepuhe.count('?'))
                else:
                    valsi = sepuhe.strip().split()
                    j = jarco (valsi)
                    jarco_xire (j)
            elif char == '/':
                valsi = sepuhe.strip().split()
                j, ni_mipri, mipri = ro_selkai_sisku (valsi)
                #    print (codes['red'] +
                #           ('\nNot displaying excessive number (%d) of search results.\n' %
                #           len(j)) + xruti + 'Please refine your search.\n')
                dukse = False
                if len(j) > 64:
                    print ('HE1')
                    dukse = True
                    #XXX jundi le se cuxna nu jarco kei


                    #XX stuff . jarco_xire should be more flexible sera'a lo se benji

                mipri = list (mipri)
                mipri.sort()
                if ni_mipri > 0:
                    print ('\t%s%d%s [ %s ] results omitted' %\
                            (cmavo_skari, ni_mipri, xruti,
                             gismu_skari + (xruti + ", " + gismu_skari).join (mipri) +\
                             xruti ))
                j = jarco (j)
                print ('dukse %r' % dukse)
                if dukse == True:
#                    print ('HE')
                    import tempfile
                    from subprocess import call
                    _, tebai_cmene = tempfile.mkstemp()
                    print ('writing to %r'% tebai_cmene)
                    tebai = open (tebai_cmene, 'wb')
                    #tebai.
                    jarco_xire (j, tebai)
                    tebai.close()
                    call (['less','-r', tebai_cmene])
                    os.remove (tebai_cmene)
                else:
                    jarco_xire (j)
            elif char == ':':
                if sepuhe [0] != '?':
                    vreji_pa_notci (sepuhe)
                else:
                    jarco_le_ka_vlalihi_pe_le_notci (10)
            elif char == '%':
                ni_selvimcu = 0
                for pagbu in sepuhe.split():
                    if pagbu in ro_valsi and valsi_datni[pagbu]['type'] != 'lujvo':
                        ni_selvimcu += 1
                        continue # ignore known valsi that are not lujvo.
                    try:
                        zasni = lujvo_katna (pagbu)
                        print (". ".join(zasni))
                        valsi = []
                        for v in zasni:
                            if len (v) > 2:
                                if len (v) == 4 and "'" not in v:
                                    valsi.append (mapti_gismu (v+'y',0))
                                else:
                                    # look for a rafsi, then a cmavo.
                                    mulno = False
                                    for v2,d in valsi_datni.items():
                                        # prefer rafsi to cmavo. .i le rafsi be fa zo ca'e mu'a
                                        if d['rafsi'] != None and v in d['rafsi']:
                                            valsi.append (v2)
                                            mulno = True
                                            break
                                    if not mulno:
                                        for v2,d in valsi_datni.items():
                                            if v2 == v:
                                                valsi.append (v)
                                                break
                        print (valsi)
                        j = jarco (valsi)
                        jarco_xire (j)
                    except IndexError:
                        print ("bad lujvo morphology for %r. ignored." % pagbu)
                    except ValueError:
                        print ("bad lujvo morphology for %r. ignored." % pagbu)
                if ni_selvimcu > 0:
                    print ('%d non-lujvo valsi ignored' % ni_selvimcu)
            vreji_pa_pruce_datni (sepuhe)
            continue
        else:
            from subprocess import Popen, PIPE
            try:
                f = Popen (fadyselcuha, stdin = PIPE, stdout = PIPE)
                f.stdin.write (sepuhe)
            except OSError:
                print ('Your default parser (%r) doesn\'t appear to be present!' % fadyselcuha[0])
                print ('Please fix your setting in ~/.jbofacki.cfg to point at a valid executable.')
                sys.exit()
        purci = sepuhe
        f.stdin.close()
        tepuhe = f.stdout.read()
        f.stdout.close()

        sys.stdout.write (tepuhe)
        sys.stdout.write ('\n')
        sys.stdout.flush ()

        vreji_pa_pruce_datni (sepuhe)
        vreji_pa_pruce_datni (tepuhe)

if __name__ == "__main__":
    main()
back to top