def proof(self, event=None): """ Builds an RTF version of the story. Pass whether to open the destination file afterwards. """ # ask for our destination dialog = wx.FileDialog(self, 'Proof Story', os.getcwd(), "", \ "RTF Document (*.rtf)|*.rtf", \ wx.SAVE | wx.FD_OVERWRITE_PROMPT | wx.FD_CHANGE_DIR) if dialog.ShowModal() == wx.ID_OK: path = dialog.GetPath() dialog.Destroy() else: dialog.Destroy() return try: # open destination for writing dest = open(path, 'w') # assemble our tiddlywiki and write it out tw = TiddlyWiki() for widget in self.storyPanel.sortedWidgets(): tw.addTiddler(widget.passage) order = map(lambda w: w.passage.title, self.storyPanel.sortedWidgets()) dest.write(tw.toRtf(order)) dest.close() except: self.app.displayError('building a proofing copy of your story')
def exportSource(self, event=None): """Asks the user to choose a file to export source to, then exports the wiki.""" dialog = wx.FileDialog( self, "Export Source Code", os.getcwd(), "", "Text File (*.txt)|*.txt", wx.SAVE | wx.FD_OVERWRITE_PROMPT | wx.FD_CHANGE_DIR, ) if dialog.ShowModal() == wx.ID_OK: try: path = dialog.GetPath() tw = TiddlyWiki() for widget in self.storyPanel.widgets: tw.addTiddler(widget.passage) dest = open(path, "w") order = map(lambda w: w.passage.title, self.storyPanel.sortedWidgets()) dest.write(tw.toTwee(order)) dest.close() except: self.app.displayError("exporting your source code") dialog.Destroy()
def importHtml (self, event = None): """Asks the user to choose a file to import HTML tiddlers from, then imports into the current story.""" dialog = wx.FileDialog(self, 'Import From Compiled HTML', os.getcwd(), '', \ 'HTML Twine game (*.html;* .htm; *.txt)|*.html;*.htm;*.txt|All Files (*.*)|*.*', wx.OPEN | wx.FD_CHANGE_DIR) if dialog.ShowModal() == wx.ID_OK: try: # have a TiddlyWiki object parse it for us tw = TiddlyWiki() tw.addHtmlFromFilename(dialog.GetPath()) # add passages for each of the tiddlers the TiddlyWiki saw if len(tw.tiddlers): lastpos = [0, 0] for t in tw.tiddlers: tiddler = tw.tiddlers[t] new = self.storyPanel.newWidget(title = tiddler.title, text = tiddler.text, \ pos = tiddler.pos if tiddler.pos != None else lastpos, \ logicals = True, quietly = True) lastpos = new.pos new.passage.tags = tiddler.tags self.setDirty(True, 'Import') else: dialog = wx.MessageDialog(self, 'No passages were found in this file. Make sure ' + \ 'this is a Twine game file.', 'No Passages Found', \ wx.ICON_INFORMATION | wx.OK) dialog.ShowModal() except: self.app.displayError('importing from HTML')
def importSource (self, event = None): """Asks the user to choose a file to import source from, then imports into the current story.""" dialog = wx.FileDialog(self, 'Import Source Code', os.getcwd(), '', \ 'Twee File (*.twee;* .tw; *.txt)|*.twee;*.tw;*.txt|All Files (*.*)|*.*', wx.OPEN | wx.FD_CHANGE_DIR) if dialog.ShowModal() == wx.ID_OK: try: # have a TiddlyWiki object parse it for us tw = TiddlyWiki() tw.addTweeFromFilename(dialog.GetPath()) # add passages for each of the tiddlers the TiddlyWiki saw if len(tw.tiddlers): lastpos = [0, 0] for t in tw.tiddlers: tiddler = tw.tiddlers[t] new = self.storyPanel.newWidget(title = tiddler.title, text = tiddler.text, quietly = True, pos = lastpos) new.passage.tags = tiddler.tags lastpos = new.pos self.setDirty(True, 'Import') else: dialog = wx.MessageDialog(self, 'No passages were found in this file. Make sure ' + \ 'this is a Twee source file.', 'No Passages Found', \ wx.ICON_INFORMATION | wx.OK) dialog.ShowModal() except: self.app.displayError('importing your source code')
def importSource(self, event=None): """Asks the user to choose a file to import source from, then imports into the current story.""" dialog = wx.FileDialog(self, 'Import Source Code', os.getcwd(), '', \ 'Twee File (*.twee;* .tw; *.txt)|*.twee;*.tw;*.txt|All Files (*.*)|*.*', wx.OPEN | wx.FD_CHANGE_DIR) if dialog.ShowModal() == wx.ID_OK: try: # have a TiddlyWiki object parse it for us tw = TiddlyWiki() tw.addTweeFromFilename(dialog.GetPath()) # add passages for each of the tiddlers the TiddlyWiki saw if len(tw.tiddlers): for t in tw.tiddlers: tiddler = tw.tiddlers[t] new = self.storyPanel.newWidget(title=tiddler.title, text=tiddler.text, quietly=True) new.tags = tiddler.tags self.setDirty(True, 'Import') else: dialog = wx.MessageDialog(self, 'No passages were found in this file. Make sure ' + \ 'this is a Twee source file.', 'No Passages Found', \ wx.ICON_INFO | wx.OK) dialog.ShowModal() except: self.app.displayError('importing your source code')
def proof (self, event = None): """ Builds an RTF version of the story. Pass whether to open the destination file afterwards. """ # ask for our destination dialog = wx.FileDialog(self, 'Proof Story', os.getcwd(), "", \ "RTF Document (*.rtf)|*.rtf", \ wx.SAVE | wx.FD_OVERWRITE_PROMPT | wx.FD_CHANGE_DIR) if dialog.ShowModal() == wx.ID_OK: path = dialog.GetPath() dialog.Destroy() else: dialog.Destroy() return try: # open destination for writing dest = open(path, 'w') # assemble our tiddlywiki and write it out tw = TiddlyWiki() for widget in self.storyPanel.sortedWidgets(): tw.addTiddler(widget.passage) order = map(lambda w: w.passage.title, self.storyPanel.sortedWidgets()) dest.write(tw.toRtf(order)) dest.close() except: self.app.displayError('building a proofing copy of your story')
def getPlugins(repo, store): """ retrieve and store plugins from repository @param repo (list): repository dictionaries @param store (Store): TiddlyWeb store @return (bool): success """ if repo["type"] == "TiddlyWiki": try: html = urlopen(repo["URI"]).read() # TODO: deferred processing?! log.append("STATUS: retrieved repository '%s' (%s)" % (repo["name"], repo["URI"])) except IOError: log.append("ERROR: could not process repository '%s'" % repo["name"]) return False bag = Bag(repo["name"]) tw = TiddlyWiki(html) tw.convertStoreFormat() plugins = tw.getPluginTiddlers(repo) empty = "<html><body><div id='storeArea'>\n</div></body></html>" # XXX: ugly hack; cf. tiddlywiki.TiddlyWiki.getPluginTiddlers() if plugins != empty: savePlugins(store, bag) import_wiki(store, plugins, bag.name) return True else: log.append("WARNING: repository '%s' does not contain any plugins" % repo["name"]) return False elif repo["type"] == "SVN": bag = Bag(repo["name"]) svn = DirScraper(repo["URI"]) try: plugins = svn.getPlugins("./", True) log.append("STATUS: retrieved repository '%s' (%s)" % (repo["name"], repo["URI"])) except IOError: log.append("ERROR: could not process repository '%s'" % repo["name"]) return False if plugins: savePlugins(store, bag) for plugin in plugins: plugin.bag = bag.name store.put(plugin) return True else: log.append("WARNING: repository '%s' contains no plugins" % repo["name"]) return False else: pass # XXX: TBD
def exportSource (self, event = None): """Asks the user to choose a file to export source to, then exports the wiki.""" dialog = wx.FileDialog(self, 'Export Source Code', os.getcwd(), "", \ 'Twee File (*.twee;* .tw; *.txt)|*.twee;*.tw;*.txt|All Files (*.*)|*.*', wx.SAVE | wx.FD_OVERWRITE_PROMPT | wx.FD_CHANGE_DIR) if dialog.ShowModal() == wx.ID_OK: try: path = dialog.GetPath() tw = TiddlyWiki() for widget in self.storyPanel.widgets: tw.addTiddler(widget.passage) dest = codecs.open(path, 'w', 'utf-8-sig', 'replace') order = map(lambda w: w.passage.title, self.storyPanel.sortedWidgets()) dest.write(tw.toTwee(order)) dest.close() except: self.app.displayError('exporting your source code') dialog.Destroy()
def build (self): tw = TiddlyWiki('twee') dest = open(self.destination, 'w') for source in self.sources: file = open(source) tw.add_twee(file.read()) file.close() header = open(self.getTargetPath() + self.target + os.sep + 'header.html') dest.write(header.read()) header.close() dest.write(tw.to_html()) dest.write('</div></html>') dest.close() return True
def exportSource(self, event=None): """Asks the user to choose a file to export source to, then exports the wiki.""" dialog = wx.FileDialog(self, 'Export Source Code', os.getcwd(), "", \ 'Twee File (*.twee;* .tw; *.txt)|*.twee;*.tw;*.txt|All Files (*.*)|*.*', wx.SAVE | wx.FD_OVERWRITE_PROMPT | wx.FD_CHANGE_DIR) if dialog.ShowModal() == wx.ID_OK: try: path = dialog.GetPath() tw = TiddlyWiki() for widget in self.storyPanel.widgets: tw.addTiddler(widget.passage) dest = codecs.open(path, 'w', 'utf-8-sig', 'replace') order = map(lambda w: w.passage.title, self.storyPanel.sortedWidgets()) dest.write(tw.toTwee(order)) dest.close() except: self.app.displayError('exporting your source code') dialog.Destroy()
def rebuild (self, event = None, displayAfter = False): """ Builds an HTML version of the story. Pass whether to open the destination file afterwards. """ try: # open destination for writing dest = open(self.buildDestination, 'w') # assemble our tiddlywiki and write it out tw = TiddlyWiki() for widget in self.storyPanel.widgets: tw.addTiddler(widget.passage) dest.write(tw.toHtml(self.app, self.target).encode('utf-8')) dest.close() if displayAfter: self.viewBuild() except: self.app.displayError('building your story')
def importSource(self, event=None): """Asks the user to choose a file to import source from, then imports into the current story.""" dialog = wx.FileDialog( self, "Import Source Code", os.getcwd(), "", "Text Files (*.txt)|*.txt|Twee Source Code (*.tw)|*.tw", wx.OPEN | wx.FD_CHANGE_DIR, ) if dialog.ShowModal() == wx.ID_OK: try: # have a TiddlyWiki object parse it for us source = open(dialog.GetPath(), "rb") tw = TiddlyWiki() tw.addTwee(source.read()) source.close() # add passages for each of the tiddlers the TiddlyWiki saw if len(tw.tiddlers): for t in tw.tiddlers: tiddler = tw.tiddlers[t] new = self.storyPanel.newWidget(title=tiddler.title, text=tiddler.text, quietly=True) new.tags = tiddler.tags self.setDirty(True, "Import") else: dialog = wx.MessageDialog( self, "No passages were found in this file. Make sure " + "this is a Twee source file.", "No Passages Found", wx.ICON_INFO | wx.OK, ) dialog.ShowModal() except: self.app.displayError("importing your source code")
def rebuild (self, event = None, displayAfter = False): """ Builds an HTML version of the story. Pass whether to open the destination file afterwards. """ try: # Remember current working dir and set to savefile's dir. InterTwine StoryIncludes are relative to the Twine file. cwd = os.getcwd() if self.saveDestination == '': twinedocdir = cwd else: twinedocdir = os.path.dirname(self.saveDestination) os.chdir(twinedocdir) # assemble our tiddlywiki and write it out hasstartpassage = False tw = TiddlyWiki() for widget in self.storyPanel.widgets: if widget.passage.title != 'StoryIncludes' and \ not any(t.startswith('Twine.') for t in widget.passage.tags): widget.passage.pos = widget.pos tw.addTiddler(widget.passage) if widget.passage.title == "Start": hasstartpassage = True # is there a Start passage? if hasstartpassage == False: self.app.displayError('building your story because there is no "Start" passage. ' + "\n" + 'Your story will build but the web browser will not be able to run the story. ' + "\n" + 'Please add a passage with the title "Start"') for widget in self.storyPanel.widgets: if widget.passage.title == 'StoryIncludes': lines = widget.passage.text.splitlines() lines.append(''); # State 0: Look for a filename ## State 1: have filename, look for filename, EXCEPT, INCLUDE, ALIAS ## State 2: EXCEPT mode, look for INCLUDE 3, ALIAS 4 or blank line 0 ## State 3: INCLUDE mode, look for EXCEPT 2, ALIAS 4 or blank line 0 ## State 4: ALIAS mode, look for EXCEPT 2, INCLUDE 2 or blank line 0 state = 0; state_filename = ''; excludepassages = TiddlyWiki.INFO_PASSAGES + ['Start'] for line in lines: if state == 0: state_filename = line state = 1 continue elif state == 1: try: if state_filename.strip() != '': extension = os.path.splitext(state_filename)[1] if extension == '.tws': if any(state_filename.startswith(t) for t in ['http://', 'https://', 'ftp://']): openedFile = urllib.urlopen(state_filename) else: openedFile = open(state_filename, 'r') s = StoryFrame(None, app = self.app, state = pickle.load(openedFile)) openedFile.close() for widget in s.storyPanel.widgets: if not any(widget.passage.title in t for t in excludepassages) and \ not any('Twine.private' in t for t in widget.passage.tags) and \ not any('Twine.system' in t for t in widget.passage.tags): tw.addTiddler(widget.passage) s.Destroy() elif extension == '.tw' or extension == '.txt' or extension == '.twee': if any(state_filename.startswith(t) for t in ['http://', 'https://', 'ftp://']): openedFile = urllib.urlopen(state_filename) s = openedFile.read() openedFile.close() t = tempfile.NamedTemporaryFile(delete=False) cleanuptempfile = True t.write(s) t.close() filename = t.name else: filename = state_filename cleanuptempfile = False tw1 = TiddlyWiki() tw1.addTweeFromFilename(filename) if cleanuptempfile: os.remove(filename) tiddlerkeys = tw1.tiddlers.keys() for tiddlerkey in tiddlerkeys: passage = tw1.tiddlers[tiddlerkey] if not any(passage.title == t for t in excludepassages) and \ not any('Twine.private' in t for t in passage.tags) and \ not any('Twine.system' in t for t in passage.tags): tw.addTiddler(passage) else: raise 'File format not recognized' except: self.app.displayError('opening the Twine file named ' + state_filename + ' which is referred to by the passage StoryIncludes') state_filename = line state = 1 continue break # Decode story settings for widget in self.storyPanel.widgets: if widget.passage.title == 'StorySettings': lines = widget.passage.text.splitlines() for line in lines: try: (skey,svalue) = line.split(':') tw.storysettings[skey.strip().lower()] = svalue.strip().lower() except: tw.storysettings[line.strip().lower()] = "true" break # Write the output file os.chdir(os.path.dirname(self.buildDestination)) dest = open(self.buildDestination, 'w') dest.write(tw.toHtml(self.app, self.target).encode('utf-8')) dest.close() os.chdir(cwd) if displayAfter: self.viewBuild() except: self.app.displayError('building your story')
def main (argv): # defaults author = 'twee' target = 'jonah' merge = rss_output = '' plugins = [] # read command line switches try: opts, args = getopt.getopt(argv, 'a:m:p:r:t:', ['author=', 'merge=', 'plugins=', 'rss=', 'target=']) except getopt.GetoptError: usage() sys.exit(2) for opt, arg in opts: if (opt in ('-a', '--author')): author = arg elif (opt in ('-m', '--merge')): merge = arg elif (opt in ('-p', '--plugins')): plugins = arg.split(',') elif (opt in ('-r', '--rss')): rss_output = arg elif (opt in ('-t', '--target')): target = arg # construct a TW object tw = TiddlyWiki(author) # read in a file to be merged if merge != '': file = open(merge) tw.addHtml(file.read()) file.close() # read source files sources = [] for arg in args: for file in glob.glob(arg): sources.append(file) if len(sources) == 0: print 'twee: no source files specified\n' sys.exit(2) for source in sources: file = open(source) tw.addTwee(file.read()) file.close() # generate RSS if requested if rss_output != '': rss_file = open(rss_output, 'w') tw.toRss().write_xml(rss_file) rss_file.close() # output the target header # if (target != 'none') and (target != 'plugin'): # file = open(scriptPath + os.sep + 'targets' + os.sep + target \ # + os.sep + 'header.html') # print(file.read()) # file.close() # the tiddlers print TwParser(tw)
def rebuild(self, event=None, displayAfter=False): """ Builds an HTML version of the story. Pass whether to open the destination file afterwards. """ try: # Remember current working dir and set to savefile's dir. InterTwine StoryIncludes are relative to the Twine file. cwd = os.getcwd() if self.saveDestination == '': twinedocdir = cwd else: twinedocdir = os.path.dirname(self.saveDestination) os.chdir(twinedocdir) if not self.storyPanel.findWidget('StoryIncludePassages'): self.storyPanel.newWidget(title='StoryIncludePassages', pos=(-1000, -1000), quietly=True) self.storyPanel.findWidget( 'StoryIncludePassages').passage.tags.append('Twine.hide') self.storyPanel.findWidget( 'StoryIncludePassages').passage.tags.append('Twine.system') self.storyPanel.findWidget('StoryIncludePassages').pos = [ -1000, -1000 ] else: self.storyPanel.findWidget( 'StoryIncludePassages').passage.tags[:] = ['Twine.hide'] self.storyPanel.findWidget( 'StoryIncludePassages').passage.tags.append('Twine.system') self.storyPanel.findWidget('StoryIncludePassages').pos = [ -1000, -1000 ] # assemble our tiddlywiki and write it out hasstartpassage = False tw = TiddlyWiki() for widget in self.storyPanel.widgets: # if widget.passage.title != 'StoryIncludes' and \ # not any('Twine.private' in t for t in widget.passage.tags) and \ # not any('Twine.system' in t for t in widget.passage.tags): if widget.passage.title != 'StoryIncludes' and \ not any(t.startswith('Twine.') for t in widget.passage.tags): tw.addTiddler(widget.passage) if widget.passage.title == "Start": hasstartpassage = True # is there a Start passage? if hasstartpassage == False: self.app.displayError( 'building your story because there is no "Start" passage. ' + "\n" + 'Your story will build but the web-browser will not be able to run the story. ' + "\n" + 'Please add a passage with the title "Start"') for widget in self.storyPanel.widgets: if widget.passage.title == 'StoryIncludes': lines = widget.passage.text.splitlines() lines.append('') # State 0: Look for a filename ## State 1: have filename, look for filename, EXCEPT, INCLUDE, ALIAS ## State 2: EXCEPT mode, look for INCLUDE 3, ALIAS 4 or blank line 0 ## State 3: INCLUDE mode, look for EXCEPT 2, ALIAS 4 or blank line 0 ## State 4: ALIAS mode, look for EXCEPT 2, INCLUDE 2 or blank line 0 state = 0 state_filename = '' excludepassages = [ 'Start', 'StoryMenu', 'StoryTitle', 'StoryAuthor', 'StorySubtitle', 'StoryIncludes', 'StorySettings' ] for line in lines: if state == 0: state_filename = line state = 1 continue elif state == 1: try: if state_filename.strip() != '': extension = os.path.splitext( state_filename)[1] if extension == '.tws': if any( state_filename.startswith(t) for t in ['http://', 'https://', 'ftp://']): openedFile = urllib.urlopen( state_filename) else: openedFile = open( state_filename, 'r') s = StoryFrame( None, app=self.app, state=pickle.load(openedFile)) openedFile.close() for widget in s.storyPanel.widgets: if not any(widget.passage.title in t for t in excludepassages) and \ not any('Twine.private' in t for t in widget.passage.tags) and \ not any('Twine.system' in t for t in widget.passage.tags): tw.addTiddler(widget.passage) if self.storyPanel.findWidget( 'StoryIncludePassages' ): self.storyPanel.findWidget( 'StoryIncludePassages' ).passage.tags.append( widget.passage.title) s.Destroy() elif extension == '.tw' or extension == '.txt' or extension == '.twee': if any( state_filename.startswith(t) for t in ['http://', 'https://', 'ftp://']): openedFile = urllib.urlopen( state_filename) s = openedFile.read() openedFile.close() t = tempfile.NamedTemporaryFile( delete=False) cleanuptempfile = True t.write(s) t.close() filename = t.name else: filename = state_filename cleanuptempfile = False tw1 = TiddlyWiki() tw1.addTweeFromFilename(filename) if cleanuptempfile: os.remove(filename) tiddlerkeys = tw1.tiddlers.keys() for tiddlerkey in tiddlerkeys: passage = tw1.tiddlers[tiddlerkey] if not any(passage.title == t for t in excludepassages) and \ not any('Twine.private' in t for t in passage.tags) and \ not any('Twine.system' in t for t in passage.tags): tw.addTiddler(passage) if self.storyPanel.findWidget( 'StoryIncludePassages' ): self.storyPanel.findWidget( 'StoryIncludePassages' ).passage.tags.append( passage.title) else: raise 'File format not recognized' except: self.app.displayError( 'opening the Twine file named ' + state_filename + ' which is referred to by the passage StoryIncludes' ) state_filename = line state = 1 continue break # Decode story settings for widget in self.storyPanel.widgets: if widget.passage.title == 'StorySettings': lines = widget.passage.text.splitlines() for line in lines: (skey, svalue) = line.split(':') tw.storysettings[skey.strip()] = svalue.strip() break # Write the output file os.chdir(os.path.dirname(self.buildDestination)) dest = open(self.buildDestination, 'w') dest.write( tw.toHtml(self.app, self.target, savePath=self.saveDestination).encode('utf-8')) dest.close() os.chdir(cwd) if displayAfter: self.viewBuild() except: self.app.displayError('building your story')
from tiddlywiki import TiddlyWiki tw5 = TiddlyWiki.parse_from_html('./example/tw5.html') predicate = lambda t: 'journal' in t.tags journal_tiddlers = list(tw5.finditer(predicate)) for tiddler in journal_tiddlers: tiddler.open_in_browser() for tiddler in journal_tiddlers: tiddler.export_to_file('./example/' + tiddler.title + '.pdf') tw5.export_to_file('./example/tw5_journal.pdf', '--toc', key=lambda t: t.created, predicates=[predicate]) tw5.open_in_browser(key=lambda t: t.created, predicates=[predicate])
def main(argv): parser = argparse.ArgumentParser( description="Convert twee source code into SAM source code") parser.add_argument("-a", "--author", default="twee") parser.add_argument("-m", "--merge", default="") parser.add_argument("-p", "--plugins", nargs="*", default=[]) parser.add_argument("-r", "--rss", default="") parser.add_argument("-t", "--target", default="jonah") parser.add_argument("sources") parser.add_argument("destination") opts = parser.parse_args() # construct a TW object tw = TiddlyWiki(opts.author) # read in a file to be merged if opts.merge: with io.open(opts.merge, encoding="utf-8-sig") as f: tw.addHtml(f.read()) # read source files sources = glob.glob(opts.sources) if not sources: logging.error('twee2sam: no source files specified\n') sys.exit(2) for source in sources: with io.open(source, encoding="utf-8-sig") as f: tw.addTwee(f.read()) src_dir = os.path.dirname(sources[0]) # # Parse the file # twp = TwParser(tw) # # Number the passages # passage_indexes = {} def process_passage_index(passage): global next_seq if not passage.title in passage_indexes: passage_indexes[passage.title] = process_passage_index.next_seq process_passage_index.next_seq += 1 process_passage_index.next_seq = 0 # 'Start' _must_ be the first script if not 'Start' in twp.passages: logging.error('twee2sam: "Start" passage not found.\n') sys.exit(2) process_passage_index(twp.passages['Start']) for passage in twp.passages.values(): process_passage_index(passage) # # Generate the file list # passage_order = [ psg for psg, idx in sorted(passage_indexes.items(), key=itemgetter(1)) ] def name_to_identifier(s): return re.sub(r'[^0-9A-Za-z]', '_', s) def script_name(s): return name_to_identifier(s) + '.twsam' if not os.path.exists(opts.destination): os.makedirs(opts.destination) with io.open(os.path.join(opts.destination, 'Script.list.txt'), 'w', encoding="utf-8") as f_list: for passage_name in passage_order: passage = twp.passages[passage_name] f_list.write(u"%s" % script_name(passage.title)) f_list.write(u'\n') # # Generate SAM scripts # # A is used as a temp var for menu selection # B is used as a temp var for menu selection # C and above are available variables = VariableFactory(2) image_list = [] music_list = [] for passage in twp.passages.values(): with io.open(os.path.join(opts.destination, script_name(passage.title)), 'w', encoding="utf-8") as script: def check_print(): if check_print.pending: script.write(u'!\n') check_print.in_buffer = 0 check_print.pending = False check_print.pending = False check_print.in_buffer = 0 def warning(msg): logging.warning("Warning on \'{0}\': {1}".format( passage.title, msg)) def out_string(msg): MAX_LEN = 512 # go through the string and replace characters msg = ''.join( map( lambda x: { '"': "'", '[': '{', ']': '}' }[x] if x in ('"', '[', '{') else x, msg)) msg_len = len(msg) # Checks for buffer overflow if check_print.in_buffer + msg_len > MAX_LEN - 1: warning( "The text exceeds the maximum buffer size; try to intersperse the text with some <<pause>> macros" ) remaining = max(0, MAX_LEN - 1 - check_print.in_buffer) msg = msg[:remaining] script.write(u'"{0}"'.format(msg)) script.write(u'\n') check_print.in_buffer += len(msg) def out_set(cmd): out_expr(cmd.expr) script.write(u' ') target = variables.set_var(cmd.target) script.write(u"%s\n" % target) def out_if(cmd): out_expr(cmd.expr) script.write(u'[\n') process_command_list(cmd.children, True) script.write(u' 0]\n') def out_print(cmd): # print a numeric qvariable out_expr(cmd.expr) script.write(u'"\#"') def out_expr(expr): def var_locator(name): return variables.get_var(name).replace(':', '') generated = twexpression.to_sam(expr, var_locator=var_locator) script.write(u"%s" % generated) def out_call(cmd): call_target = None for k in passage_indexes.keys(): if cmd.target == k: call_target = passage_indexes[k] if call_target: script.write(u"%s" % call_target) script.write(u'c\n') def out_jump(cmd): call_target = None for k in passage_indexes.keys(): if cmd.target == k: call_target = passage_indexes[k] if call_target: script.write(u"%s" % call_target) script.write(u'j\n') # Outputs all the text links = [] def register_link(cmd, is_conditional): temp_var = variables.new_temp_var() if is_conditional else None links.append((cmd, temp_var)) if temp_var: script.write(u'1%s' % variables.set_var(temp_var)) def process_command_list(commands, is_conditional=False): for cmd in commands: if cmd.kind == 'text': text = cmd.text.strip() if text: out_string(cmd.text) check_print.pending = True elif cmd.kind == 'print': out_print(cmd) elif cmd.kind == 'image': check_print() if not cmd.path in image_list: image_list.append(cmd.path) script.write(u'{0}i\n'.format( image_list.index(cmd.path))) elif cmd.kind == 'link': register_link(cmd, is_conditional) out_string(cmd.actual_label()) elif cmd.kind == 'list': for lcmd in cmd.children: if lcmd.kind == 'link': register_link(lcmd, is_conditional) elif cmd.kind == 'pause': check_print.pending = True check_print() elif cmd.kind == 'set': out_set(cmd) elif cmd.kind == 'if': out_if(cmd) elif cmd.kind == 'call': out_call(cmd) elif cmd.kind == 'jump': out_jump(cmd) elif cmd.kind == 'return': script.write(u'$\n') elif cmd.kind == 'music': if not cmd.path in music_list: music_list.append(cmd.path) script.write(u'{0}m\n'.format( music_list.index(cmd.path))) elif cmd.kind == 'display': try: target = twp.passages[cmd.target] except KeyError: logging.error( "Display macro target passage {0} not found!". format(cmd.target), file=sys.stderr) return process_command_list(target.commands) process_command_list(passage.commands) check_print() # Builds the menu from the links if links: # Outputs the options separated by line breaks, max 28 chars per line for link, temp_var in links: if temp_var: script.write(u'{0}['.format( variables.get_var(temp_var))) out_string(link.actual_label()[:28] + '\n') if temp_var: script.write(u'0]\n') script.write(u'?A.\n') check_print.in_buffer = 0 # Outputs the menu destinations script.write(u'0B.\n') for link, temp_var in links: if temp_var: script.write(u'{0}['.format( variables.get_var(temp_var))) if not link.target in passage_indexes: # TODO: Create a better exception raise BaseException( 'Link points to a nonexisting passage: "{0}"'. format(link.target)) script.write(u'A:B:=[{0}j]'.format( passage_indexes[link.target])) script.write(u'B:1+B.\n') if temp_var: script.write(u'0]\n') else: # No links? Generates an infinite loop. script.write(u'1[1]\n') # # Function to copy the files on a list and generate a list file # def copy_and_build_list(list_file_name, file_list, item_extension, item_suffix='', empty_item='blank'): with io.open(os.path.join(opts.destination, list_file_name), 'w', encoding="utf-8") as list_file: for file_path in file_list: item_name = name_to_identifier( os.path.splitext(os.path.basename(file_path))[0]) list_file.write("%s%s\n" % (item_name, item_suffix)) shutil.copyfile( os.path.join(src_dir, file_path), os.path.join(opts.destination, '%s.%s' % (item_name, item_extension))) if not file_list: list_file.write(u"%s%s\n" % (empty_item, item_suffix)) # # Copy images and builds the image list # copy_and_build_list('Images.txt', image_list, 'png') # # Copy music and builds the music list # copy_and_build_list('Music.list.txt', music_list, 'epsgmod', '.epsgmod', 'empty')
def import_tiddlers(predicate): tw5 = TiddlyWiki.parse_from_html('./_wiki/index.html') guide_tiddlers = list(tw5.finditer(predicate)) for tiddler in guide_tiddlers: tiddler.export_to_file(source_dir + tiddler.title + '.md')
def main (argv): parser = argparse.ArgumentParser(description="Convert twee source code into SAM source code") parser.add_argument("-a", "--author", default="twee") parser.add_argument("-m", "--merge", default="") parser.add_argument("-p", "--plugins", nargs="*", default=[]) parser.add_argument("-r", "--rss", default="") parser.add_argument("-t", "--target", default="jonah") parser.add_argument("sources") parser.add_argument("destination") opts = parser.parse_args() # construct a TW object tw = TiddlyWiki(opts.author) # read in a file to be merged if opts.merge: with io.open(opts.merge, encoding="utf-8-sig") as f: tw.addHtml(f.read()) # read source files sources = glob.glob(opts.sources) if not sources: logging.error('twee2sam: no source files specified\n') sys.exit(2) for source in sources: with io.open(source, encoding="utf-8-sig") as f: tw.addTwee(f.read()) src_dir = os.path.dirname(sources[0]) # # Parse the file # twp = TwParser(tw) # # Number the passages # passage_indexes = {} def process_passage_index(passage): global next_seq if not passage.title in passage_indexes: passage_indexes[passage.title] = process_passage_index.next_seq process_passage_index.next_seq += 1 process_passage_index.next_seq = 0 # 'Start' _must_ be the first script if not 'Start' in twp.passages: logging.error('twee2sam: "Start" passage not found.\n') sys.exit(2) process_passage_index(twp.passages['Start']) for passage in twp.passages.values(): process_passage_index(passage) # # Generate the file list # passage_order = [psg for psg, idx in sorted(passage_indexes.items(), key=itemgetter(1))] def name_to_identifier(s): return re.sub(r'[^0-9A-Za-z]', '_', s) def script_name(s): return name_to_identifier(s) + '.twsam' if not os.path.exists(opts.destination): os.makedirs(opts.destination) with io.open(os.path.join(opts.destination, 'Script.list.txt'), 'w', encoding="utf-8") as f_list: for passage_name in passage_order: passage = twp.passages[passage_name] f_list.write(u"%s" % script_name(passage.title)) f_list.write(u'\n') # # Generate SAM scripts # # A is used as a temp var for menu selection # B is used as a temp var for menu selection # C and above are available variables = VariableFactory(2) image_list = [] music_list = [] for passage in twp.passages.values(): with io.open(os.path.join(opts.destination, script_name(passage.title)), 'w', encoding="utf-8") as script: def check_print(): if check_print.pending: script.write(u'!\n') check_print.in_buffer = 0 check_print.pending = False check_print.pending = False check_print.in_buffer = 0 def warning(msg): logging.warning("Warning on \'{0}\': {1}".format(passage.title, msg)) def out_string(msg): MAX_LEN = 512 # go through the string and replace characters msg = ''.join(map(lambda x: {'"': "'", '[': '{', ']':'}'}[x] if x in ('"','[','{') else x, msg)) msg_len = len(msg) # Checks for buffer overflow if check_print.in_buffer + msg_len > MAX_LEN - 1: warning("The text exceeds the maximum buffer size; try to intersperse the text with some <<pause>> macros") remaining = max(0, MAX_LEN - 1 - check_print.in_buffer) msg = msg[:remaining] script.write(u'"{0}"'.format(msg)) script.write(u'\n') check_print.in_buffer += len(msg) def out_set(cmd): out_expr(cmd.expr) script.write(u' ') target = variables.set_var(cmd.target) script.write(u"%s\n" % target) def out_if(cmd): out_expr(cmd.expr) script.write(u'[\n') process_command_list(cmd.children, True) script.write(u' 0]\n') def out_print(cmd): # print a numeric qvariable out_expr(cmd.expr) script.write(u'"\#"') def out_expr(expr): def var_locator(name): return variables.get_var(name).replace(':', '') generated = twexpression.to_sam(expr, var_locator = var_locator) script.write(u"%s" % generated) def out_call(cmd): call_target = None for k in passage_indexes.keys(): if cmd.target == k: call_target = passage_indexes[k] if call_target: script.write(u"%s" % call_target) script.write(u'c\n') # Outputs all the text links = [] def register_link(cmd, is_conditional): temp_var = variables.new_temp_var() if is_conditional else None links.append((cmd, temp_var)) if temp_var: script.write(u'1%s' % variables.set_var(temp_var)) def process_command_list(commands, is_conditional=False): for cmd in commands: if cmd.kind == 'text': text = cmd.text.strip() if text: out_string(text) check_print.pending = True elif cmd.kind == 'print': out_print(cmd) elif cmd.kind == 'image': check_print() if not cmd.path in image_list: image_list.append(cmd.path) script.write(u'{0}i\n'.format(image_list.index(cmd.path))) elif cmd.kind == 'link': register_link(cmd, is_conditional) out_string(cmd.actual_label()) elif cmd.kind == 'list': for lcmd in cmd.children: if lcmd.kind == 'link': register_link(lcmd, is_conditional) elif cmd.kind == 'pause': check_print.pending = True check_print() elif cmd.kind == 'set': out_set(cmd) elif cmd.kind == 'if': out_if(cmd) elif cmd.kind == 'call': out_call(cmd) elif cmd.kind == 'return': script.write(u'$\n') elif cmd.kind == 'music': if not cmd.path in music_list: music_list.append(cmd.path) script.write(u'{0}m\n'.format(music_list.index(cmd.path))) elif cmd.kind == 'display': try: target = twp.passages[cmd.target] except KeyError: logging.error("Display macro target passage {0} not found!".format(cmd.target), file=sys.stderr) return process_command_list(target.commands) process_command_list(passage.commands) check_print() # Builds the menu from the links if links: # Outputs the options separated by line breaks, max 28 chars per line for link, temp_var in links: if temp_var: script.write(u'{0}['.format(variables.get_var(temp_var))) out_string(link.actual_label()[:28] + '\n') if temp_var: script.write(u'0]\n') script.write(u'?A.\n') check_print.in_buffer = 0 # Outputs the menu destinations script.write(u'0B.\n'); for link, temp_var in links: if temp_var: script.write(u'{0}['.format(variables.get_var(temp_var))) if not link.target in passage_indexes: # TODO: Create a better exception raise BaseException('Link points to a nonexisting passage: "{0}"'.format(link.target)) script.write(u'A:B:=[{0}j]'.format(passage_indexes[link.target])) script.write(u'B:1+B.\n') if temp_var: script.write(u'0]\n') else: # No links? Generates an infinite loop. script.write(u'1[1]\n') # # Function to copy the files on a list and generate a list file # def copy_and_build_list(list_file_name, file_list, item_extension, item_suffix = '', empty_item = 'blank'): with io.open(os.path.join(opts.destination, list_file_name), 'w', encoding="utf-8") as list_file: for file_path in file_list: item_name = name_to_identifier(os.path.splitext(os.path.basename(file_path))[0]) list_file.write("%s%s\n" % (item_name, item_suffix)) shutil.copyfile(os.path.join(src_dir, file_path), os.path.join(opts.destination, '%s.%s' % (item_name, item_extension))) if not file_list: list_file.write(u"%s%s\n" % (empty_item, item_suffix)) # # Copy images and builds the image list # copy_and_build_list('Images.txt', image_list, 'png') # # Copy music and builds the music list # copy_and_build_list('Music.list.txt', music_list, 'epsgmod', '.epsgmod', 'empty')