github.com/jmigpin/editor@v1.6.0/core/openerow.go (about)

     1  package core
     2  
     3  import (
     4  	"errors"
     5  
     6  	"github.com/jmigpin/editor/ui"
     7  	"github.com/jmigpin/editor/util/iout/iorw"
     8  	"github.com/jmigpin/editor/util/parseutil"
     9  )
    10  
    11  type OpenFileERowConfig struct {
    12  	FilePos *parseutil.FilePos
    13  	RowPos  *ui.RowPos
    14  
    15  	CancelIfExistent      bool
    16  	NewIfNotExistent      bool
    17  	NewIfOffsetNotVisible bool
    18  
    19  	//FlashRowsIfNotFlashed bool
    20  	FlashVisibleOffsets bool // flashes rows if not visible
    21  }
    22  
    23  // TODO: make it UI safe? rename to openfileerowasync?
    24  func OpenFileERow(ed *Editor, conf *OpenFileERowConfig) {
    25  	if _, err := openFileERow2(ed, conf); err != nil {
    26  		ed.Error(err)
    27  	}
    28  }
    29  
    30  func openFileERow2(ed *Editor, conf *OpenFileERowConfig) (isNew bool, _ error) {
    31  	// filename
    32  	var filename string
    33  	if conf.FilePos != nil {
    34  		filename = conf.FilePos.Filename
    35  	} else {
    36  		return false, errors.New("missing filename")
    37  	}
    38  
    39  	info := ed.ReadERowInfo(filename)
    40  
    41  	// do nothing if existent
    42  	if conf.CancelIfExistent && len(info.ERows) > 0 {
    43  		return false, nil
    44  	}
    45  
    46  	createNew := false
    47  
    48  	// helper func: cache for LineColumnIndex
    49  	lciVal := 0
    50  	lciDone := false
    51  	cacheLineColumnIndex := func(rd iorw.ReaderAt) int {
    52  		if lciDone {
    53  			return lciVal
    54  		}
    55  		lciDone = true
    56  		if conf.FilePos.Line == 0 { // missing line/col, should be ">=1"
    57  			lciVal = -1
    58  		} else {
    59  			u, err := parseutil.LineColumnIndex(rd, conf.FilePos.Line, conf.FilePos.Column)
    60  			if err != nil {
    61  				lciVal = -1
    62  			} else {
    63  				lciVal = u
    64  			}
    65  		}
    66  		return lciVal
    67  	}
    68  
    69  	// helper func: get offset
    70  	getOffset := func() int {
    71  		if conf.FilePos != nil {
    72  			if conf.FilePos.HasOffset() {
    73  				return conf.FilePos.Offset
    74  			}
    75  			if erow0, ok := info.FirstERow(); ok {
    76  				ta := erow0.Row.TextArea
    77  				return cacheLineColumnIndex(ta.RW())
    78  			}
    79  		}
    80  		return -1
    81  	}
    82  
    83  	// should create new if not existent
    84  	if conf.NewIfNotExistent {
    85  		if len(info.ERows) == 0 {
    86  			createNew = true
    87  		}
    88  	}
    89  
    90  	// should create new if offset not visible
    91  	if conf.NewIfOffsetNotVisible {
    92  		if !createNew {
    93  			if len(info.ERows) == 0 {
    94  				createNew = true
    95  			} else {
    96  				offset := getOffset()
    97  				if offset >= 0 {
    98  					visible := false
    99  					for _, e := range info.ERows {
   100  						if e.Row.TextArea.IndexVisible(offset) {
   101  							visible = true
   102  							break
   103  						}
   104  					}
   105  					createNew = !visible
   106  				}
   107  			}
   108  		}
   109  	}
   110  
   111  	// create new erow
   112  	var newERow *ERow
   113  	if createNew {
   114  		isNew = true
   115  		if conf.RowPos == nil {
   116  			return isNew, errors.New("missing row position")
   117  		}
   118  		erow, err := NewLoadedERow(info, conf.RowPos)
   119  		if err != nil {
   120  			return isNew, err
   121  		}
   122  		newERow = erow
   123  	}
   124  
   125  	// make offset visible
   126  	flashed := make(map[*ERow]bool)
   127  	offset := getOffset()
   128  	if offset >= 0 {
   129  		if len(info.ERows) == 0 {
   130  			return isNew, errors.New("missing erow to make offset visible")
   131  		}
   132  
   133  		// use newly created erow
   134  		erow := newERow
   135  
   136  		// use existing row with visible offset
   137  		if erow == nil {
   138  			for _, e := range info.ERows {
   139  				if e.Row.TextArea.IndexVisible(offset) {
   140  					erow = e
   141  					break
   142  				}
   143  			}
   144  		}
   145  
   146  		// use first row in UI order
   147  		if erow == nil {
   148  			erow = info.ERowsInUIOrder()[0]
   149  		}
   150  
   151  		// setup chosen erow
   152  		//erow.Row.EnsureTextAreaMinimumHeight()
   153  		erow.Row.EnsureOneToolbarLineYVisible()
   154  		erow.Row.TextArea.Cursor().SetIndexSelectionOff(offset)
   155  		erow.Row.TextArea.MakeIndexVisible(offset)
   156  
   157  		// flash visible offsets
   158  		if conf.FlashVisibleOffsets {
   159  			o, l := 0, 0
   160  			if conf.FilePos != nil {
   161  				if conf.FilePos.HasOffset() {
   162  					o, l = conf.FilePos.Offset, conf.FilePos.Len
   163  				} else {
   164  					o = offset
   165  				}
   166  			}
   167  
   168  			for _, e := range info.ERows {
   169  				if e.Row.TextArea.IndexVisible(offset) {
   170  					e.MakeRangeVisibleAndFlash(o, l)
   171  					flashed[e] = true
   172  				}
   173  			}
   174  		}
   175  
   176  		// no flashes were done (no index visible, small rows), flash target
   177  		if len(flashed) == 0 {
   178  			erow.Flash()
   179  			flashed[erow] = true
   180  		}
   181  	}
   182  
   183  	// flash rows if not flashed already
   184  	//if conf.FlashRowsIfNotFlashed ||
   185  	if conf.FlashVisibleOffsets && offset < 0 {
   186  		for _, e := range info.ERows {
   187  			if !flashed[e] {
   188  				e.Flash()
   189  			}
   190  		}
   191  	}
   192  
   193  	return isNew, nil
   194  }