Source File
bidi.go
Belonging Package
vendor/golang.org/x/text/unicode/bidi
// Copyright 2015 The Go Authors. All rights reserved.// Use of this source code is governed by a BSD-style// license that can be found in the LICENSE file.//go:generate go run gen.go gen_trieval.go gen_ranges.go// Package bidi contains functionality for bidirectional text support.//// See https://www.unicode.org/reports/tr9.//// NOTE: UNDER CONSTRUCTION. This API may change in backwards incompatible ways// and without notice.package bidi // import "golang.org/x/text/unicode/bidi"// TODO// - Transformer for reordering?// - Transformer (validator, really) for Bidi Rule.import ()// This API tries to avoid dealing with embedding levels for now. Under the hood// these will be computed, but the question is to which extent the user should// know they exist. We should at some point allow the user to specify an// embedding hierarchy, though.// A Direction indicates the overall flow of text.type Direction intconst (// LeftToRight indicates the text contains no right-to-left characters and// that either there are some left-to-right characters or the option// DefaultDirection(LeftToRight) was passed.LeftToRight Direction = iota// RightToLeft indicates the text contains no left-to-right characters and// that either there are some right-to-left characters or the option// DefaultDirection(RightToLeft) was passed.RightToLeft// Mixed indicates text contains both left-to-right and right-to-left// characters.Mixed// Neutral means that text contains no left-to-right and right-to-left// characters and that no default direction has been set.Neutral)type options struct {defaultDirection Direction}// An Option is an option for Bidi processing.type Option func(*options)// ICU allows the user to define embedding levels. This may be used, for example,// to use hierarchical structure of markup languages to define embeddings.// The following option may be a way to expose this functionality in this API.// // LevelFunc sets a function that associates nesting levels with the given text.// // The levels function will be called with monotonically increasing values for p.// func LevelFunc(levels func(p int) int) Option {// panic("unimplemented")// }// DefaultDirection sets the default direction for a Paragraph. The direction is// overridden if the text contains directional characters.func ( Direction) Option {return func( *options) {.defaultDirection =}}// A Paragraph holds a single Paragraph for Bidi processing.type Paragraph struct {p []byteo Orderingopts []Optiontypes []ClasspairTypes []bracketTypepairValues []runerunes []runeoptions options}// Initialize the p.pairTypes, p.pairValues and p.types from the input previously// set by p.SetBytes() or p.SetString(). Also limit the input up to (and including) a paragraph// separator (bidi class B).//// The function p.Order() needs these values to be set, so this preparation could be postponed.// But since the SetBytes and SetStrings functions return the length of the input up to the paragraph// separator, the whole input needs to be processed anyway and should not be done twice.//// The function has the same return values as SetBytes() / SetString()func ( *Paragraph) () ( int, error) {.runes = bytes.Runes(.p):= 0// clear slices from previous SetString or SetBytes.pairTypes = nil.pairValues = nil.types = nilfor , := range .runes {, := LookupRune()+=:= .Class()if == B {return , nil}.types = append(.types, )if .IsOpeningBracket() {.pairTypes = append(.pairTypes, bpOpen).pairValues = append(.pairValues, )} else if .IsBracket() {// this must be a closing bracket,// since IsOpeningBracket is not true.pairTypes = append(.pairTypes, bpClose).pairValues = append(.pairValues, )} else {.pairTypes = append(.pairTypes, bpNone).pairValues = append(.pairValues, 0)}}return , nil}// SetBytes configures p for the given paragraph text. It replaces text// previously set by SetBytes or SetString. If b contains a paragraph separator// it will only process the first paragraph and report the number of bytes// consumed from b including this separator. Error may be non-nil if options are// given.func ( *Paragraph) ( []byte, ...Option) ( int, error) {.p =.opts =return .prepareInput()}// SetString configures s for the given paragraph text. It replaces text// previously set by SetBytes or SetString. If s contains a paragraph separator// it will only process the first paragraph and report the number of bytes// consumed from s including this separator. Error may be non-nil if options are// given.func ( *Paragraph) ( string, ...Option) ( int, error) {.p = []byte().opts =return .prepareInput()}// IsLeftToRight reports whether the principle direction of rendering for this// paragraphs is left-to-right. If this returns false, the principle direction// of rendering is right-to-left.func ( *Paragraph) () bool {return .Direction() == LeftToRight}// Direction returns the direction of the text of this paragraph.//// The direction may be LeftToRight, RightToLeft, Mixed, or Neutral.func ( *Paragraph) () Direction {return .o.Direction()}// TODO: what happens if the position is > len(input)? This should return an error.// RunAt reports the Run at the given position of the input text.//// This method can be used for computing line breaks on paragraphs.func ( *Paragraph) ( int) Run {:= 0:= 0for , := range .o.runes {+= len()if < {=}}return .o.Run()}func ( []level, []rune) Ordering {var Direction:= Neutral:= 0:= Ordering{}// lvl = 0,2,4,...: left to right// lvl = 1,3,5,...: right to leftfor , := range {if %2 == 0 {= LeftToRight} else {= RightToLeft}if != {if > 0 {.runes = append(.runes, [:]).directions = append(.directions, ).startpos = append(.startpos, )}==}}.runes = append(.runes, [:]).directions = append(.directions, ).startpos = append(.startpos, )return}// Order computes the visual ordering of all the runs in a Paragraph.func ( *Paragraph) () (Ordering, error) {if len(.types) == 0 {return Ordering{}, nil}for , := range .opts {(&.options)}:= level(-1)if .options.defaultDirection == RightToLeft {= 1}, := newParagraph(.types, .pairTypes, .pairValues, )if != nil {return Ordering{},}:= .getLevels([]int{len(.types)}).o = calculateOrdering(, .runes)return .o, nil}// Line computes the visual ordering of runs for a single line starting and// ending at the given positions in the original text.func ( *Paragraph) (, int) (Ordering, error) {:= .types[:], := newParagraph(, .pairTypes[:], .pairValues[:], -1)if != nil {return Ordering{},}:= .getLevels([]int{len()}):= calculateOrdering(, .runes[:])return , nil}// An Ordering holds the computed visual order of runs of a Paragraph. Calling// SetBytes or SetString on the originating Paragraph invalidates an Ordering.// The methods of an Ordering should only be called by one goroutine at a time.type Ordering struct {runes [][]runedirections []Directionstartpos []int}// Direction reports the directionality of the runs.//// The direction may be LeftToRight, RightToLeft, Mixed, or Neutral.func ( *Ordering) () Direction {return .directions[0]}// NumRuns returns the number of runs.func ( *Ordering) () int {return len(.runes)}// Run returns the ith run within the ordering.func ( *Ordering) ( int) Run {:= Run{runes: .runes[],direction: .directions[],startpos: .startpos[],}return}// TODO: perhaps with options.// // Reorder creates a reader that reads the runes in visual order per character.// // Modifiers remain after the runes they modify.// func (l *Runs) Reorder() io.Reader {// panic("unimplemented")// }// A Run is a continuous sequence of characters of a single direction.type Run struct {runes []runedirection Directionstartpos int}// String returns the text of the run in its original order.func ( *Run) () string {return string(.runes)}// Bytes returns the text of the run in its original order.func ( *Run) () []byte {return []byte(.String())}// TODO: methods for// - Display order// - headers and footers// - bracket replacement.// Direction reports the direction of the run.func ( *Run) () Direction {return .direction}// Pos returns the position of the Run within the text passed to SetBytes or SetString of the// originating Paragraph value.func ( *Run) () (, int) {return .startpos, .startpos + len(.runes) - 1}// AppendReverse reverses the order of characters of in, appends them to out,// and returns the result. Modifiers will still follow the runes they modify.// Brackets are replaced with their counterparts.func (, []byte) []byte {:= make([]byte, len()+len())copy(, ):= bytes.Runes()for , := range {, := LookupRune()if .IsBracket() {[] = .reverseBracket()}}for , := 0, len()-1; < ; , = +1, -1 {[], [] = [], []}copy([len():], string())return}// ReverseString reverses the order of characters in s and returns a new string.// Modifiers will still follow the runes they modify. Brackets are replaced with// their counterparts.func ( string) string {:= []rune():= len():= make([]rune, )for , := range {, := LookupRune()if .IsBracket() {[--1] = .reverseBracket()} else {[--1] =}}return string()}
![]() |
The pages are generated with Golds v0.6.7. (GOOS=linux GOARCH=amd64) Golds is a Go 101 project developed by Tapir Liu. PR and bug reports are welcome and can be submitted to the issue list. Please follow @Go100and1 (reachable from the left QR code) to get the latest news of Golds. |