@@ -197,6 +197,7 @@ public final class StyledTextLibrary: NativeLibrary {
197197 self . define ( Procedure ( " load-styled-text " , loadStyledText) )
198198 self . define ( Procedure ( " copy-styled-text " , copyStyledText) )
199199 self . define ( Procedure ( " save-styled-text " , saveStyledText) )
200+ self . define ( Procedure ( " html->styled-text " , htmlToStyledText) )
200201 self . define ( Procedure ( " bytevector->styled-text " , bytevectorToStyledText) )
201202 self . define ( Procedure ( " styled-text=? " , styledTextEquals) )
202203 self . define ( Procedure ( " styled-text-string " , styledTextString) )
@@ -208,6 +209,9 @@ public final class StyledTextLibrary: NativeLibrary {
208209 self . define ( Procedure ( " styled-text-remove! " , styledTextRemove) )
209210 self . define ( Procedure ( " styled-text-attribute " , styledTextAttribute) )
210211 self . define ( Procedure ( " styled-text-attributes " , styledTextAttributes) )
212+ self . define ( Procedure ( " styled-text-first-attribute " , styledTextFirstAttribute) )
213+ self . define ( Procedure ( " styled-text-first-attributes " , styledTextFirstAttributes) )
214+ self . define ( Procedure ( " styled-text->html " , styledTextToHtml) )
211215 self . define ( Procedure ( " styled-text->bytevector " , styledTextToBytevector) )
212216
213217 // Text styles
@@ -584,6 +588,16 @@ public final class StyledTextLibrary: NativeLibrary {
584588 return . void
585589 }
586590
591+ private func htmlToStyledText( html: Expr ) throws -> Expr {
592+ let data = Data ( try html. asString ( ) . utf8)
593+ let str = try NSMutableAttributedString (
594+ data: data,
595+ options: [ . documentType: NSAttributedString . DocumentType. html,
596+ . characterEncoding: String . Encoding. utf8. rawValue] ,
597+ documentAttributes: nil )
598+ return . object( StyledText ( str) )
599+ }
600+
587601 private func bytevectorToStyledText( expr: Expr , format: Expr , args: Arguments ) throws -> Expr {
588602 let subvec = try BytevectorLibrary . subVector ( " bytevector->styled-text " , expr, args)
589603 if let docType = self . documentType ( from: try format. asSymbol ( ) ) {
@@ -731,40 +745,67 @@ public final class StyledTextLibrary: NativeLibrary {
731745 return . void
732746 }
733747
734- private func styledTextAttribute( text: Expr , index : Expr , sym : Expr , args : Arguments ) throws -> Expr {
735- guard let ( start , end ) = args . optional ( . false , . false ) else {
736- throw RuntimeError . argumentCount ( of : " styled-text-attribute " , min : 3 , max : 5 ,
737- args : . pair ( text , . pair ( index , . pair ( sym , . makeList ( args ) ) ) ) )
738- }
748+ private func styledTextAttribute( text: Expr ,
749+ sym : Expr ,
750+ index : Expr ,
751+ start : Expr ? ,
752+ end : Expr ? ) throws -> Expr {
739753 let str = try self . styledText ( from: text) . value
740- let idx = try index. asInt ( below: str. length + 1 )
741754 guard let key = self . attributeKey ( from: try sym. asSymbol ( ) ) else {
742755 throw RuntimeError . eval ( . unknownTextStyleAttribute, sym)
743756 }
744- let s = start. isTrue ? try start. asInt ( below: idx + 1 ) : 0
745- let e = end. isTrue ? try end. asInt ( above: s, below: str. length + 1 ) : str. length
757+ let idx = try index. asInt ( below: str. length + 1 )
758+ let s = start != nil && start!. isTrue ? try start!. asInt ( below: idx + 1 ) : 0
759+ let e = end != nil && end!. isTrue ? try end!. asInt ( above: s, below: str. length + 1 ) : str. length
746760 var range = NSRange ( location: 0 , length: 0 )
747761 if let value = str. attribute ( key,
748762 at: idx,
749763 longestEffectiveRange: & range,
750764 in: NSRange ( location: s, length: e - s) ) ,
751765 let res = try self . textStyleValue ( key: key, value: value) {
752766 return . values( . pair( res, . pair( . pair( . fixnum( Int64 ( range. location) ) ,
753- . fixnum( Int64 ( range. location + range. length) ) ) , . null) ) )
754- } else {
755- return . false
767+ . fixnum( Int64 ( range. location + range. length) ) ) ,
768+ . null) ) )
756769 }
770+ return . values( . pair( . false , . pair( . false , . null) ) )
757771 }
758772
759- private func styledTextAttributes( text: Expr , index: Expr , args: Arguments ) throws -> Expr {
760- guard let ( start, end) = args. optional ( . false , . false ) else {
761- throw RuntimeError . argumentCount ( of: " styled-text-attributes " , min: 2 , max: 4 ,
762- args: . pair( text, . pair( index, . makeList( args) ) ) )
773+ private func styledTextFirstAttribute( text: Expr ,
774+ sym: Expr ,
775+ start: Expr ? ,
776+ end: Expr ? ) throws -> Expr {
777+ let str = try self . styledText ( from: text) . value
778+ guard let key = self . attributeKey ( from: try sym. asSymbol ( ) ) else {
779+ throw RuntimeError . eval ( . unknownTextStyleAttribute, sym)
763780 }
781+ let s = start != nil && start!. isTrue ? try start!. asInt ( below: str. length + 1 ) : 0
782+ let e = end != nil && end!. isTrue ? try end!. asInt ( above: s, below: str. length + 1 ) : str. length
783+ var res = Expr . undef
784+ str. enumerateAttribute ( key,
785+ in: NSRange ( location: s, length: e - s) ,
786+ options: [ ] ,
787+ using: { value, range, stop in
788+ do {
789+ if let value = value,
790+ let val = try self . textStyleValue ( key: key, value: value) {
791+ res = . values( . pair( val, . pair( . pair( . fixnum( Int64 ( range. location) ) ,
792+ . fixnum( Int64 ( range. location + range. length) ) ) ,
793+ . null) ) )
794+ stop. pointee = false
795+ }
796+ } catch { }
797+ } )
798+ return res. isUndef ? . values( . pair( . false , . pair( . false , . null) ) ) : res
799+ }
800+
801+ private func styledTextAttributes( text: Expr ,
802+ index: Expr ,
803+ start: Expr ? ,
804+ end: Expr ? ) throws -> Expr {
764805 let str = try self . styledText ( from: text) . value
765806 let idx = try index. asInt ( below: str. length + 1 )
766- let s = start. isTrue ? try start. asInt ( below: idx + 1 ) : 0
767- let e = end. isTrue ? try end. asInt ( above: s, below: str. length + 1 ) : str. length
807+ let s = start != nil && start! . isTrue ? try start! . asInt ( below: idx + 1 ) : 0
808+ let e = end != nil && end! . isTrue ? try end! . asInt ( above: s, below: str. length + 1 ) : str. length
768809 var range = NSRange ( location: 0 , length: 0 )
769810 let res = TextStyle ( )
770811 res. attributes = str. attributes ( at: idx,
@@ -776,6 +817,47 @@ public final class StyledTextLibrary: NativeLibrary {
776817 . null) ) )
777818 }
778819
820+ private func styledTextFirstAttributes( text: Expr , start: Expr ? , end: Expr ? ) throws -> Expr {
821+ let str = try self . styledText ( from: text) . value
822+ let s = start != nil && start!. isTrue ? try start!. asInt ( below: str. length + 1 ) : 0
823+ let e = end != nil && end!. isTrue ? try end!. asInt ( above: s, below: str. length + 1 ) : str. length
824+ var res = Expr . undef
825+ str. enumerateAttributes ( in: NSRange ( location: s, length: e - s) ,
826+ options: [ ] ,
827+ using: { attribs, range, stop in
828+ if !attribs. isEmpty {
829+ let tstyle = TextStyle ( )
830+ tstyle. attributes = attribs
831+ res = . values( . pair( . object( tstyle) ,
832+ . pair( . pair( . fixnum( Int64 ( range. location) ) ,
833+ . fixnum( Int64 ( range. location + range. length) ) ) ,
834+ . null) ) )
835+ stop. pointee = true
836+ }
837+ } )
838+ guard res. isUndef else {
839+ return res
840+ }
841+ return . values( . pair( . false , . pair( . false , . null) ) )
842+ }
843+
844+ private func styledTextToHtml( text: Expr ,
845+ start: Expr ? ,
846+ end: Expr ? ) throws -> Expr {
847+ let str = try self . styledText ( from: text) . value
848+ let e = ( end? . isTrue ?? false ) ? try end!. asInt ( below: str. length + 1 ) : str. length
849+ let s = ( start? . isTrue ?? false ) ? try start!. asInt ( below: e + 1 ) : 0
850+ let data = try str. data (
851+ from: NSRange ( location: s, length: e - s) ,
852+ documentAttributes: [ . documentType: NSAttributedString . DocumentType. html,
853+ . characterEncoding: String . Encoding. utf8. rawValue] )
854+ if let res = String ( data: data, encoding: String . Encoding. utf8) {
855+ return . makeString( res)
856+ } else {
857+ return . false
858+ }
859+ }
860+
779861 private func styledTextToBytevector( text: Expr ,
780862 format: Expr ,
781863 start: Expr ? ,
0 commit comments