omz:forum

    • Register
    • Login
    • Search
    • Recent
    • Popular

    Welcome!

    This is the community forum for my apps Pythonista and Editorial.

    For individual support questions, you can also send an email. If you have a very short question or just want to say hello — I'm @olemoritz on Twitter.


    Rich Text Clipboard

    Pythonista
    clipboard native beta objc
    5
    15
    13480
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • omz
      omz last edited by

      I'm sorry, but there's no way to do this in 1.5.

      dshafik 1 Reply Last reply Reply Quote 0
      • dshafik
        dshafik @omz last edited by

        @omz will 2.0 be a free upgrade (whenever apple approves it)? I just bought 1.5 today…

        1 Reply Last reply Reply Quote 0
        • Webmaster4o
          Webmaster4o last edited by

          @dshafik That is the plan, yes. I'm not sure if there will be a cost increase for new users buying the app, but the upgrade should be free for existing users

          1 Reply Last reply Reply Quote 0
          • dshafik
            dshafik last edited by dshafik

            So, 2.0 is now out, and I've continued working on this. I've tried multiple approaches and none of them work:

            from objc_util import * 
            from pygments import highlight
            from pygments.lexers import PhpLexer
            from pygments.formatters import RtfFormatter
            
            code = '<?php echo "hello world"; ?>'
            rtf = highlight(code, PhpLexer(), RtfFormatter())
            
            fp = open('highlight.rtf', 'w+')
            fp.write(rtf)
            data = NSData.dataWithContentsOfFile_('highlight.rtf')
            
            c = ObjCClass('UIPasteboard')
            pasteBoard = c.generalPasteboard()
            
            pasteBoard.setValue_forPasteboardType_(data, 'public.rtf')
            

            This one results in:

            > pasteBoard.pasteboardTypes()
            <__NSCFArray: (
                "public.rtf"
            )>
            

            But I can't seem to paste it into say, Keynote (or a Word, etc.). Maybe this is an issue with Keynote , I guess.

            Maybe I could generate an image to insert? Thoughts?

            1 Reply Last reply Reply Quote 0
            • Webmaster4o
              Webmaster4o last edited by

              Generating an image shouldn't be hard. Try rendering with PIL ImageDraw.

              1 Reply Last reply Reply Quote 0
              • JonB
                JonB last edited by

                You forgot to close your file pointer.

                with open(...) as fp:    
                   fp.write(.....)
                

                worked for me.
                The giveaway: data was NSZeroData
                Also, it was not needed here, but I find it useful to use os.path.abspath, and/ or nsurl(filepath) when sending file names to objc.

                dshafik 1 Reply Last reply Reply Quote 0
                • dshafik
                  dshafik @JonB last edited by

                  @JonB I've not seen that syntax before, I assume creates a block (or some sort of scoped section) in which fp is made available and then when the block is left it is automatically closed?

                  Anyhow, I do now see data in data but I still can't get it to paste in. Were you able to do that?

                  1 Reply Last reply Reply Quote 0
                  • JonB
                    JonB last edited by

                    The "with" syntax creates a context, which automatically does some clean up when the block ends. For file handles, this means it calls .close() (even if there is an exception, etc), so many people advocate for this style of file handling. You could have also just called fp.close().

                    I have not tried pasting anything. It is not clear to me that public.rtf is supported in UIpasteboard. Does pygments support an html formatter? You might try public.html.

                    1 Reply Last reply Reply Quote 0
                    • omz
                      omz last edited by

                      I've experimented a little bit with this, and it seems to be harder than I thought. The iWork apps apparently copy rich text in some internal format that I can't figure out (com.apple.iWork.TSPNativeData), and neither RTF nor HTML appear to be supported.

                      Copying formatted text from Safari or Notes, and pasting it into Pages/Keynote doesn't work either (the formatting is discarded).

                      1 Reply Last reply Reply Quote 1
                      • omz
                        omz last edited by omz

                        If an image is acceptable for you, this might work:

                        from objc_util import * 
                        from pygments import highlight
                        from pygments.lexers import PhpLexer
                        from pygments.formatters import RtfFormatter
                        import ui
                        import clipboard
                        NSAttributedString = ObjCClass('NSAttributedString')
                        
                        code = '<?php echo "hello world"; ?>'
                        rtf = highlight(code, PhpLexer(), RtfFormatter())
                        
                        rtf_data = ns(bytearray(rtf))
                        attr_str = NSAttributedString.alloc().initWithData_options_documentAttributes_error_(rtf_data, None, None, None).autorelease()
                        size = attr_str.size()
                        with ui.ImageContext(size.width, size.height) as ctx:
                        	attr_str.drawAtPoint_(CGPoint(0.0, 0.0))
                        	img = ctx.get_image()
                        	clipboard.set_image(img)
                        

                        I'm using an NSAttributedString that is initialized from RTF data. Unfortunately, pygment's own method for rendering into images (GifImageFormatter etc.) don't work correctly in Pythonista because the method that it uses for finding system fonts fails on iOS.

                        1 Reply Last reply Reply Quote 1
                        • dshafik
                          dshafik last edited by dshafik

                          I managed to get Pygments image drawing working by monkey patching the font stuff (ick!):

                          import clipboard
                          import os
                          import _font_cache
                          from objc_util import * 
                          from pygments import highlight
                          from pygments.lexers import PhpLexer
                          from pygments.formatters import ImageFormatter
                          from pygments.formatters.img import FontManager
                          from pygments.styles import monokai
                          
                          monokai.MonokaiStyle.background_color = '#000000'
                          
                          def _get_nix_font_path(self, name, style):
                          	if style == 'bold' or style == 'italic':
                          		return _font_cache.get_font_path('%s %s' % (name, style.capitalize()))	
                          	elif style == '':
                          		return _font_cache.get_font_path(name)
                          	else:
                          		return
                          		
                          FontManager._get_nix_font_path = _get_nix_font_path
                          
                          ''' Replace Unicode newline chars with regular ones '''
                          code = clipboard.get().replace(unichr(8232), os.linesep)
                          
                          png = highlight(code, PhpLexer(startinline=True), ImageFormatter(style='monokai', font_name='Source Code Pro', font_size=60, line_numbers=False, line_pad=4))
                          
                          with open('highlight.png', 'w+') as fp:
                          	fp.write(png)
                          	
                          data = NSData.dataWithContentsOfFile_('highlight.png')
                          
                          c = ObjCClass('UIPasteboard')
                          pasteBoard = c.generalPasteboard()
                          pasteBoard.setData_forPasteboardType_(data, 'public.png')
                          os.remove('highlight.png')
                          

                          Resulting in an image like so:

                          Highlighted Source

                          1 Reply Last reply Reply Quote 1
                          • jeromecarney
                            jeromecarney last edited by

                            I've logged extensive hours working on a similar objective for the past two week -- outputting formatted text to the clipboard for a custom dictionary wrapper I've built for StarDict data -- but so far I've had no success.

                            I've been able to coerce raw html into an rtf file, which I can then pass both to an NSData object as well as an attributed string, but there's still no way I can find -- UIPasteboard with every conceivable UTI, javascript, etc., to then send the formated data along to the clipboard. The current work around is to process the data throught Workflow, but that's slow and inelegant, especially when launched from split view.

                            Is there anything in the works that would enable this functionality? It would seem to be such a basic feature.

                            1 Reply Last reply Reply Quote 0
                            • JonB
                              JonB last edited by JonB

                              This works for me, sending data to OneNote:

                              from objc_util import * 
                              from pygments import highlight
                              from pygments.lexers import PhpLexer
                              from pygments.formatters import RtfFormatter
                              p=ObjCClass('UIPasteboard').generalPasteboard()
                              code = b'<?php echo "hello world"; ?>'
                              rtf = highlight(code, PhpLexer(), RtfFormatter())
                              
                              rtf_data = ns(bytes(rtf,'ascii'))
                              p.setData_forPasteboardType_(rtf_data,'public.RTF')
                              
                              1 Reply Last reply Reply Quote 0
                              • jeromecarney
                                jeromecarney last edited by

                                Jon - thanks, you set me on the right track -- the app I want to paste into (MarginNote) accepts rich text only if it's formatted as an Apple Web Archive type. Here's how I ultimately got it to work for Python 2.7, thanks to this guide on coercing HTML into an archive type:

                                from objc_util import * 
                                import os
                                import base64
                                theDefinition = '<html><head></head><body>''<font size="5">' + '<b>Hello</b> <i>world!2</i>' + '</font></body></html>'
                                theData = base64.encodestring(theDefinition)
                                theData = str(theData)
                                theArchive = """<?xml version="1.0" encoding="UTF-8"?>
                                <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
                                <plist version="1.0">
                                 <dict>
                                  <key>WebMainResource</key>
                                  <dict>
                                   <key>WebResourceData</key>
                                   <data>
                                   """ + theData + """   </data>
                                   <key>WebResourceFrameName</key>
                                   <string></string>
                                   <key>WebResourceMIMEType</key>
                                   <string>text/html</string>
                                   <key>WebResourceTextEncodingName</key>
                                   <string>UTF-8</string>
                                   <key>WebResourceURL</key>
                                   <string>about:blank</string>
                                  </dict>
                                 </dict>
                                </plist>"""
                                thePasteBoard = ObjCClass('UIPasteboard')
                                thePasteBoard = thePasteBoard.generalPasteboard()
                                theType = "Apple Web Archive pasteboard type"
                                thePasteBoard.setValue_forPasteboardType_(theArchive,theType)
                                
                                1 Reply Last reply Reply Quote 0
                                • First post
                                  Last post
                                Powered by NodeBB Forums | Contributors