11#!/usr/bin/env python
22# Copyright 2025 by Andreas Schawo <df1asc@darc.de>, licensed under CC BY-SA 4.0
33
4+ import os
45import sys
56import json
67
78from adif_file import adi
89
9- NUSHELL_VERSION = '0. 102.0'
10- PLUGIN_VERSION = '0.1.0 '
10+ NUSHELL_VERSION = 0 , 102
11+ PLUGIN_VERSION = '0.1.1 '
1112
1213__call_command__ = ''
1314__call_id__ = None
@@ -101,15 +102,14 @@ def adif_time2iso(time: str) -> str:
101102def process_to_adi (data ):
102103 """Convert table data to ADIF string"""
103104 global __adi_doc__
104- sys .stderr .write ('to adi: ' + json .dumps (data , indent = 2 ) + '\n ' )
105105
106106 try :
107- rec_data = data [1 ][ 'List' ][ 'Record' ][ 'val' ]
107+ rec_data = data ['val' ]
108108 record = {}
109109 for f in rec_data :
110110 for t in rec_data [f ]:
111111 val = str (rec_data [f ][t ]['val' ])
112- if f .upper (). endswith ( 'DATE' ):
112+ if 'DATE' in f .upper ():
113113 val = val .replace ('-' , '' )
114114 elif f .upper ().startswith ('TIME' ):
115115 val = val .replace (':' , '' )
@@ -142,7 +142,7 @@ def process_from_adi():
142142 val = {}
143143 for f in fieldnames :
144144 rec_val : str = rec [f ] if f in rec else ''
145- if f . endswith ( 'DATE' ) :
145+ if 'DATE' in f :
146146 rec_val = adif_date2iso (rec_val )
147147 elif f .startswith ('TIME' ):
148148 rec_val = adif_time2iso (rec_val )
@@ -169,7 +169,7 @@ def tell_nushell_encoding():
169169 sys .stdout .flush ()
170170
171171
172- def tell_nushell_hello ():
172+ def tell_nushell_hello (nu_version = '' ):
173173 """
174174 A `Hello` message is required at startup to inform nushell of the protocol capabilities and
175175 compatibility of the plugin. The version specified should be the version of nushell that this
@@ -178,7 +178,7 @@ def tell_nushell_hello():
178178 hello = {
179179 'Hello' : {
180180 'protocol' : 'nu-plugin' , # always this value
181- 'version' : NUSHELL_VERSION ,
181+ 'version' : nu_version ,
182182 'features' : [],
183183 }
184184 }
@@ -187,13 +187,13 @@ def tell_nushell_hello():
187187 sys .stdout .flush ()
188188
189189
190- def write_response (id , response ):
190+ def write_response (call_id , response ):
191191 """
192192 Format a response to a plugin call.
193193 """
194194 wrapped_response = {
195195 'CallResponse' : [
196- id ,
196+ call_id ,
197197 response ,
198198 ]
199199 }
@@ -202,14 +202,14 @@ def write_response(id, response):
202202 sys .stdout .flush ()
203203
204204
205- def write_error (id , text , span = None ):
205+ def write_error (call_id , text , span = None ):
206206 """
207207 Format error response to nushell.
208208 """
209209 error = (
210210 {
211211 'Error' : {
212- 'msg' : 'ERROR from plugin' ,
212+ 'msg' : 'ADI plugin error ' ,
213213 'labels' : [
214214 {
215215 'text' : text ,
@@ -221,40 +221,45 @@ def write_error(id, text, span=None):
221221 if span is not None
222222 else {
223223 'Error' : {
224- 'msg' : 'ERROR from plugin' ,
224+ 'msg' : 'ADI plugin error ' ,
225225 'help' : text ,
226226 }
227227 }
228228 )
229- write_response (id , error )
229+ write_response (call_id , error )
230230
231231
232- def handle_input (input ):
233- global __call_command__ , __call_id__ , __call_span__ , __adi_doc__
232+ def handle_input (input_data ):
233+ global __call_command__ , __call_id__ , __call_span__ , __adi_doc__ , __adi_table__
234234
235- if 'Hello' in input :
236- if input ['Hello' ]['version' ] != NUSHELL_VERSION :
237- exit (1 )
238- else :
239- return
240- elif input == 'Goodbye' :
235+ if 'Hello' in input_data :
236+ match input_data :
237+ case {'Hello' : {'version' : nu_ver }}:
238+ major , minor , patch = [int (part ) for part in nu_ver .split ('.' )]
239+ if major == NUSHELL_VERSION [0 ] and minor >= NUSHELL_VERSION [1 ]:
240+ return
241+ else :
242+ write_error (__call_id__ ,
243+ f'Nushell version { nu_ver } does not match. Required Nushell >= { NUSHELL_VERSION } ' )
244+
245+ elif input_data == 'Goodbye' :
241246 exit (0 )
242- elif 'Call' in input :
243- [id , plugin_call ] = input ['Call' ]
247+ elif 'Call' in input_data :
248+ [call_id , plugin_call ] = input_data ['Call' ]
244249 if plugin_call == 'Metadata' :
245250 write_response (
246- id ,
251+ call_id ,
247252 {
248253 'Metadata' : {
249254 'version' : PLUGIN_VERSION ,
250255 }
251256 },
252257 )
253258 elif plugin_call == 'Signature' :
254- write_response (id , signatures ())
259+ write_response (call_id , signatures ())
255260 elif 'Run' in plugin_call :
256261 __call_command__ = plugin_call ['Run' ]['name' ]
257- __call_id__ = id
262+ __call_id__ = call_id
258263 __call_span__ = plugin_call ['Run' ]['call' ]['head' ]
259264
260265 if __call_command__ == 'to adi' :
@@ -272,20 +277,22 @@ def handle_input(input):
272277 comment = 'Exported by ADIF Nushell-Plugin' ,
273278 linebreaks = False ).__next__ () + '\n '
274279 else :
275- write_error (id , 'Operation not supported: ' + str (plugin_call ))
276- elif 'Data' in input :
280+ write_error (call_id , 'Operation not supported: ' + str (plugin_call ))
281+ elif 'Data' in input_data :
277282 if __call_command__ == 'to adi' :
278- process_to_adi (input ['Data' ])
283+ match input_data ['Data' ]:
284+ case [_, {'List' : {'Record' : data }}]:
285+ process_to_adi (data )
279286 elif __call_command__ == 'from adi' :
280- match input ['Data' ]:
287+ match input_data ['Data' ]:
281288 case [_, {'Raw' : {'Ok' : data }}]:
282289 __adi_doc__ += bytes (data ).decode ('utf8' )
283290 case [_, {'Raw' : {'Err' : text }}]:
284291 write_error (__call_id__ , text , __call_span__ )
285292 else :
286293 sys .stderr .write (f'Data for unknown call name: "{ __call_command__ } "' )
287- sys .stderr .write ('Data: ' + str (input ['Data' ]) + '\n ' )
288- elif 'End' in input :
294+ sys .stderr .write ('Data: ' + str (input_data ['Data' ]) + '\n ' )
295+ elif 'End' in input_data :
289296 if __call_command__ == 'to adi' :
290297 val = {
291298 'String' : {
@@ -314,22 +321,29 @@ def handle_input(input):
314321 }
315322 }
316323 write_response (__call_id__ , p_data )
317- exit (0 )
324+ elif 'Signal' in input_data :
325+ if input_data ['Signal' ] == 'Reset' :
326+ __call_command__ = ''
327+ __call_id__ = None
328+ __call_span__ = None
329+ __adi_table__ = []
330+ __adi_doc__ = ''
331+ elif input_data ['Signal' ] == 'Interrupt' :
332+ exit (1 )
318333 else :
319- sys .stderr .write ('Unknown message: ' + str (input ) + '\n ' )
334+ sys .stderr .write ('Unknown message: ' + str (input_data ) + '\n ' )
320335 exit (1 )
321336
322337
323- def plugin ():
338+ def plugin (nu_version = '' ):
324339 tell_nushell_encoding ()
325- tell_nushell_hello ()
340+ tell_nushell_hello (nu_version )
326341 for line in sys .stdin :
327- input = json .loads (line )
328- handle_input (input )
342+ handle_input (json .loads (line ))
329343
330344
331345if __name__ == '__main__' :
332346 if len (sys .argv ) == 2 and sys .argv [1 ] == '--stdio' :
333- plugin ()
347+ plugin (os . environ . get ( 'NU_VERSION' , '' ) )
334348 else :
335- print ('Run me from inside nushell!' )
349+ print ('Run me from inside nushell to unlock the magic !' )
0 commit comments