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

     1  package lsproto
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"sync"
     7  
     8  	"github.com/jmigpin/editor/util/ctxutil"
     9  )
    10  
    11  type LangManager struct {
    12  	Reg *Registration // accessed from editor
    13  
    14  	man *Manager
    15  	mu  struct {
    16  		sync.Mutex
    17  		li             *LangInstance
    18  		cancelInstance context.CancelFunc
    19  	}
    20  }
    21  
    22  func NewLangManager(man *Manager, reg *Registration) *LangManager {
    23  	return &LangManager{Reg: reg, man: man}
    24  }
    25  
    26  func (lang *LangManager) instance(reqCtx context.Context) (*LangInstance, error) {
    27  	lang.mu.Lock()
    28  	defer lang.mu.Unlock()
    29  
    30  	if lang.mu.li != nil {
    31  		return lang.mu.li, nil
    32  	}
    33  
    34  	// setup instance context // TODO: manager ctx
    35  	ctx, cancel := context.WithCancel(context.Background())
    36  
    37  	// call cancel if reqCtx is done
    38  	clearWatching := ctxutil.WatchDone(cancel, reqCtx)
    39  	defer clearWatching()
    40  
    41  	li, err := NewLangInstance(ctx, lang)
    42  	if err != nil {
    43  		cancel()
    44  		err = lang.WrapError(err)
    45  		return nil, err
    46  	}
    47  
    48  	// handle server/client abnormal early exit
    49  	go func() {
    50  		defer cancel()
    51  		if err := li.Wait(); err != nil {
    52  			lang.PrintWrapError(err)
    53  		}
    54  		// ensure this instance is cleared
    55  		lang.mu.Lock()
    56  		defer lang.mu.Unlock()
    57  		if lang.mu.li == li {
    58  			lang.mu.li = nil
    59  		}
    60  	}()
    61  
    62  	lang.mu.li = li
    63  	lang.mu.cancelInstance = cancel
    64  
    65  	return li, nil
    66  }
    67  
    68  // returns true if the instance was running
    69  func (lang *LangManager) Close() (error, bool) {
    70  	lang.mu.Lock()
    71  	defer lang.mu.Unlock()
    72  	if lang.mu.li != nil {
    73  		lang.mu.cancelInstance()
    74  		lang.mu.li = nil
    75  		return nil, true
    76  	}
    77  	return nil, false
    78  }
    79  
    80  //----------
    81  
    82  func (lang *LangManager) PrintWrapError(err error) {
    83  	lang.man.Error(lang.WrapError(err))
    84  }
    85  
    86  func (lang *LangManager) WrapError(err error) error {
    87  	return fmt.Errorf("lsproto(%s): %w", lang.Reg.Language, err)
    88  }
    89  
    90  func (lang *LangManager) WrapMsg(s string) string {
    91  	return fmt.Sprintf("lsproto(%s): %v", lang.Reg.Language, s)
    92  }